source: svn/newcon3bcm2_21bu/nexus/modules/transport/7552/src/nexus_playpump.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: 67.0 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_playpump.c $
39 * $brcm_Revision: 114 $
40 * $brcm_Date: 12/20/11 1:43p $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/transport/7400/src/nexus_playpump.c $
47 *
48 * 114   12/20/11 1:43p vsilyaev
49 * SW7425-2034: Used 32-bit type for program id (pid) types
50 *
51 * 113   12/19/11 10:06a erickson
52 * SW7425-1795: validate driver-side CPU accessibility of playback fifo
53 *
54 * 112   12/9/11 5:22p bandrews
55 * SW7550-772: merge to main
56 *
57 * SW7550-772/1   12/9/11 4:07p bandrews
58 * SW7550-772: change playpump to always use the default timebase, instead
59 *  of possibly using no timebase
60 *
61 * 111   12/5/11 10:43a erickson
62 * SW7231-497: allow NEXUS_PlaypumpOpenSettings.fifoSize = 0 for
63 *  scatter/gather-only usage
64 *
65 * 110   11/29/11 11:39a erickson
66 * SW7420-2129: get current default heap using NEXUS_P_DefaultHeap
67 *
68 * 109   11/2/11 3:55p mward
69 * SW7346-523: Fix compile error if !BXPT_HAS_32BIT_PB_TIMESTAMPS.
70 *
71 * 108   10/31/11 7:48p bandrews
72 * SW7231-391: merge to main
73 *
74 * SW7420-2078/3   10/28/11 3:49p bandrews
75 * SW7231-391: update timebase to a pointer
76 *
77 * SW7420-2078/2   10/27/11 8:07p bandrews
78 * SW7231-391: merge from main
79 *
80 * 107   10/28/11 1:27p erickson
81 * SW7346-523: extend NEXUS_TransportTimestamp to handle 32 bit timestamps
82 *  and to be more explicit about 28/30 bit timestamps
83 *
84 * 106   10/26/11 9:30a erickson
85 * SW7346-525: apply pacingOffsetAdjustDisable using XPT PI, not PB0-only
86 *  register write
87 *
88 * 105   10/17/11 11:38a gmullen
89 * SW7425-1383:  Merged to main
90 *
91 * SW7425-1383/2   10/14/11 4:09p gmullen
92 * SW7425-1383: Updated per David's suggestions
93 *
94 * SW7425-1383/1   10/11/11 3:45p gmullen
95 * SW7425-1383: Added API to return the chip-specific allPass PID channel
96 *  number
97 *
98 * SW7420-2078/1   10/25/11 5:22p bandrews
99 * SW7231-391: update parser band and timebase implementations to use
100 *  handles everywhere, even for legacy enum usage
101 *
102 * 104   9/14/11 12:11p jtna
103 * SW7420-2054: enforce boundsHeap for scatter-gather
104 *
105 * 103   9/8/11 10:56a erickson
106 * SW7408-284: add comment explaining 32/30_2U/28_4P timestamp modes for
107 *  live, playback and record
108 *
109 * 102   9/2/11 12:40p erickson
110 * SW7420-1995: unregister handles from objdb when doing automatic close
111 *
112 * 101   8/2/11 2:53p erickson
113 * SW7420-1978: use BXPT_PB_SYNC_MPEG for TS for all silicon
114 *
115 * 100   7/21/11 7:06p jtna
116 * SW7125-1015: assert pNumConsumed in
117 *  NEXUS_Playpump_SubmitScatterGatherDescriptor()
118 *
119 * 99   7/21/11 2:28p jtna
120 * SW7125-1015: added NEXUS_Playpump_SubmitScatterGatherDescriptor()
121 *
122 * 98   5/12/11 3:41p jtna
123 * SW7550-739: replace all instances of 'NEXUS_HAS_DMA &&
124 *  NEXUS_HAS_SECURITY' with 'NEXUS_ENCRYPTED_DVR_WITH_M2M'. replace some
125 *  instances of 'NEXUS_HAS_DMA' with 'NEXUS_NUM_DMA_CHANNELS'
126 *
127 * 97   3/8/11 6:08p vsilyaev
128 * SW7422-101: Updated logic of handling continuityCountEnabled, so per
129 *  band and per pid settings are combined with logical AND
130 *
131 * 96   2/28/11 12:00p hongtaoz
132 * SW7425-93, SW7425-39: remove hardcoded PES pacing timebase setting
133 *  which is set properly now by stream mux;
134 *
135 * 95   2/25/11 4:46p vsilyaev
136 * SW7422-107, SW7425-39: Fixed typo
137 *
138 * 94   2/22/11 7:53p vsilyaev
139 * SW7422-107: Added FLV mapping
140 *
141 * 93   1/28/11 8:55a erickson
142 * SW7420-1440: add internal hooks so that NEXUS_PidChannel_Close can
143 *  close playpump pidchannels (but not playback pidchannels)
144 *
145 * 92   1/17/11 9:31a erickson
146 * SW7425-68: add NEXUS_TransportModuleSettings.mainHeapIndex
147 *
148 * 91   12/30/10 7:41p vsilyaev
149 * SW7425-39: Removed special timestamp mode
150 *
151 * 90   12/30/10 6:42p vsilyaev
152 * SW7425-39: Use special timestamp mode for mux
153 *
154 * 89   12/28/10 5:44p vsilyaev
155 * SW7425-39: Added Mux specific interfaces
156 *
157 * 88   12/27/10 12:18p erickson
158 * SW7425-39: fix warning
159 *
160 * 87   12/23/10 3:25p vsilyaev
161 * SW7425-39: Start/stop playpump inside mux
162 *
163 * 86   12/16/10 6:12p vsilyaev
164 * SW7425-39: Added playpump private API
165 *
166 * 85   12/16/10 5:05p erickson
167 * SW7125-763: restore micropause after flush
168 *
169 * 84   12/13/10 6:59p vsilyaev
170 * SW7425-39: Added support for MUX input
171 *
172 * 83   12/9/10 9:50a erickson
173 * SW7420-1148: fix warning
174 *
175 * 82   12/7/10 5:46p erickson
176 * SW7420-1148: added null_allowed, boundsHeap
177 *
178 * 81   11/5/10 12:28p gmohile
179 * SW7422-20 : Use BXPT_HAS_PID_CHANNEL_PES_FILTERING instead of
180 *  BXPT_P_MAX_PACKETIZERS_PER_PB
181 *
182 * 80   11/3/10 4:32p erickson
183 * SW7422-20: use BXPT_P_MAX_PACKETIZERS_PER_PB instead of
184 *  NEXUS_SW_VOB_SUPPORT
185 *
186 * 79   10/28/10 5:09p erickson
187 * SW7422-20: adapt to new XPT PI (backward compat using magnum and nexus
188 *  macros)
189 *
190 * 78   10/1/10 9:41a erickson
191 * SW7420-1009: support NEXUS_ANY_ID
192 *
193 * 77   9/13/10 6:02p spothana
194 *  SW7420-662: Increase the number of playback channels supported
195 *
196 * 76   8/18/10 12:26p vsilyaev
197 * SW3556-1175: Added substream ID mapping for EAC3 audio
198 *
199 * 75   8/10/10 3:33p erickson
200 * SW7420-934: rename NEXUS_Playpump_ReadComplete to
201 *  NEXUS_Playpump_WriteComplete
202 *
203 * 74   6/11/10 6:58p mphillip
204 * SW7125-463: Allow the user to configure DMA data format in playpump
205 *
206 * 73   6/7/10 6:23p mphillip
207 * SW7550-398: Update examples and transport code to support non-DMA
208 *  encrypted PVR
209 *
210 * 72   4/9/10 1:07p jgarrett
211 * SW7405-4034: Moving MSDRM PD/ND binaries into nexus as required
212 *
213 * DrmMakefileUpdates/2   4/9/10 10:40a jgarrett
214 * SW7405-4034: Removing stale MSDRM lines regarding ASF decryption
215 *
216 * DrmMakefileUpdates/1   4/8/10 4:46p jgarrett
217 * SW7405-4034: Including binaries for MSDRM (PD/ND) in the nexus builds
218 *  to avoid link issues
219 *
220 * 71   1/21/10 5:56p vsilyaev
221 * SW3556-1003: Added option to disable timestamp reordering inside bmedia
222 *
223 * 70   12/29/09 12:51p erickson
224 * SW7550-146: allow security module to be initialized after the transport
225 *  module if HW requires it
226 *
227 * 69   11/3/09 9:56a erickson
228 * SW7405-3308: add TEI error callback
229 *
230 * 68   10/22/09 4:14p erickson
231 * SW7405-3245: fix playpump bprofile support
232 *
233 * 67   10/1/09 5:03p erickson
234 * SW7405-3087: add playpump cc check, add cc error counting per pid
235 *
236 * 66   8/19/09 1:49p gmohile
237 * PR 57814 : Add dvd vob support for 7401
238 *
239 * 65   6/11/09 5:05p jtna
240 * PR55767: added NEXUS_PlaypumpSettings.timestamp.forceRestamping
241 *
242 * 64   6/11/09 4:31p jtna
243 * PR55817: make check on duplicate channels backward-compatible
244 *
245 * 63   6/9/09 3:09p jtna
246 * PR55767: refactor timestamp record
247 *
248 * 62   6/8/09 3:47p erickson
249 * PR55817: relax the check on duplicate pid channels. they are allowed,
250 *  as long as they are simultaneously enabled. we still prevent duplicate
251 *  NEXUS_PidChannelHandle entries.
252 *
253 * 61   6/3/09 7:12p mward
254 * PR 51821: Set the AlwaysResumeFromLastDescriptor = true in
255 *  NEXUS_Playpump_Open() also, to avoid warnings from XPT.
256 *
257 * PR51821/1   6/1/09 12:23p vsilyaev
258 * PR 51821: Always append chain to the last playback descriptor
259 *
260 * 59   6/1/09 8:45a erickson
261 * PR55461: set PARSER_FORCE_RESTAMP for pcr-based pacing
262 *
263 * 58   5/28/09 2:41p erickson
264 * PR55461: use BXPT_HAS_PCR_PACING
265 *
266 * 57   5/28/09 11:31a erickson
267 * PR55461: add PCR-based pacing
268 *
269 * 56   5/19/09 3:02p vsilyaev
270 * PR 55299: Fixed PES PID mapping for the case of multiple audio tracks
271 *
272 * 55   5/15/09 12:48p vsilyaev
273 * PR 55193: Added function to return last parsed PTS by the media library
274 *
275 * 54   5/14/09 10:40a jtna
276 * PR54515: workaround for playpump_open() dependency on security module
277 *
278 * 53   4/20/09 10:53a erickson
279 * PR53662: rework XPT power management code to call BXPT_P_CanPowerDown
280 *  before powering down core
281 *
282 * 52   4/17/09 2:35p katrep
283 * PR50207: Reverting back previous changes
284 *
285 * 50   1/26/09 11:03a vsilyaev
286 * PR 51579: Adding originalTransportType to the PlaypumpSettings
287 *
288 * 49   12/30/08 8:55a vsilyaev
289 * PR 50606: Added hooks for hardware support of MPEG1 system streams
290 *
291 * 48   12/21/08 6:01p nickh
292 * PR50605: Fix compile errors when running without Security
293 *
294 * 47   12/17/08 12:19a erickson
295 * PR50231: clean up failed NEXUS_Playpump_Open
296 *
297 * 46   12/10/08 7:36p vsilyaev
298 * PR 48908: Added control of power management
299 *
300 * 45   12/8/08 2:39p erickson
301 * PR49993: added NEXUS_TaskCallback_Destroy
302 *
303 * 44   12/4/08 3:29p vsilyaev
304 * PR 49993: Added code to inform application about errors detected during
305 *  stream parsing
306 *
307 * 43   12/2/08 2:23p jgarrett
308 * PR 47993: Fixing substream ID mapping to allow proper substream ID's to
309 *  be passed from the application
310 *
311 * 42   11/21/08 8:54a erickson
312 * PR49531: don't flush if not started
313 *
314 * 41   10/30/08 10:27p erickson
315 * PR47132: added NEXUS_PlaypumpSettings.blindSync
316 *
317 * 40   10/29/08 1:58p erickson
318 * PR47132: set BXPT_Playback_ParserConfig.ErrorInputIgnore and
319 *  AcceptAdapt00 to true to allow raw data to pass through. no reason to
320 *  exclude this data, like the current ContCountIgnore default.
321 *
322 * 39   10/27/08 11:20a erickson
323 * PR47232: added pacingTsRangeError to NEXUS_PlaypumpStatus
324 *
325 * 38   10/24/08 4:41p erickson
326 * PR47232: allow timebase to change on the fly
327 *
328 * 37   10/22/08 11:39a erickson
329 * PR48216: allow transport to run with no dma or security modules
330 *
331 * 36   10/17/08 3:01p katrep
332 * PR47951: Add index playpump status structure
333 *
334 * 35   10/13/08 9:41a erickson
335 * PR47232: set BXPT_Playback_ParserConfig.TsMode
336 *
337 * 34   10/9/08 5:49p erickson
338 * PR47232: more timestamp impl
339 *
340 * 33   10/9/08 10:06a erickson
341 * PR47232: set additional timebase setting for
342 *  NEXUS_PlaypumpSettings.timestamp.timebase
343 *
344 * 32   10/7/08 11:31p erickson
345 * PR47232: extend NEXUS_PlaypumpSettings timestamp settings. reorganized
346 *  into a nested structure.
347 *
348 * 31   10/6/08 1:59a erickson
349 * PR47232: added NEXUS_Playpump_SetPause for IP STB throttling
350 *
351 * 30   10/6/08 1:30a erickson
352 * PR47232: added NEXUS_PlaypumpSettings.pacingMaxError
353 *
354 * 29   9/22/08 10:03a erickson
355 * PR47145: fix warning
356 *
357 * 28   9/4/08 12:46p vishk
358 * PR 46315: Sample code for PID remapping
359 *
360 * 27   8/14/08 5:25p katrep
361 * PR45674: Fix compiiler warning in kernel mode non debug builds
362 *
363 * 26   7/29/08 3:07p erickson
364 * PR45199: added NEXUS_PlaypumpSettings.maxDataRate
365 *
366 * 25   7/28/08 3:33p erickson
367 * PR45124: fix misspellings
368 *
369 * 24   7/24/08 7:55a gmullen
370 * PR42365: Use MPEG blind sync mode for Directv playback.
371 *
372 * 23   6/25/08 5:50p vsilyaev
373 * PR 41869: Use keySlotHandle instead of keySlot[Number]
374 *
375 * 22   6/17/08 12:39p vsilyaev
376 * PR 42739: Fixed reference counter
377 *
378 * 21   6/17/08 11:26a vsilyaev
379 * PR 42739: Fixed NO PVR build
380 *
381 * 20   6/17/08 10:53a vsilyaev
382 * PR 42739: Added support for duplicate pids
383 *
384 * 19   6/13/08 6:43p erickson
385 * PR43087: fix warnings if NEXUS_NUM_PLAYPUMPS=0
386 *
387 * 18   6/3/08 11:57a jgarrett
388 * PR 43279: Correcting size argument
389 *
390 * 17   5/28/08 7:45p jrubio
391 * PR43085: fix PLAYPUMP=0 compile
392 *
393 * 16   5/16/08 1:56p erickson
394 * PR42758: add NEXUS_TransportType_eVob support
395 *
396 * 15   5/14/08 1:25p vsilyaev
397 * PR 42119: Preserve PES->TS packetizer settings over
398 *  Playpump_Stop/Playpump_Start calls. PR 41869:
399 *
400 * 14   5/9/08 11:34a erickson
401 * PR42119: preserve originalTransportType for media-framework streams
402 *
403 * 13   5/7/08 10:24p vsilyaev
404 * PR 41869: Added DMA into the playpump_crypto
405 *
406 * 12   5/7/08 2:00p vsilyaev
407 * PR 41869: Added core for re-packetize MPEG-2 TS data for encrypted PVR
408 *
409 * 11   5/5/08 1:34p vsilyaev
410 * PR 42355: Reset media playRate on stop
411 *
412 * 10   4/28/08 11:53a erickson
413 * PR42197: remove NEXUS_ParserBand_ePlayback enums
414 *
415 * 9   4/25/08 1:01p erickson
416 * PR41951: NEXUS_Playpump_Stop should call flush before stopping
417 *  PVRlib_Feed_Stop
418 *
419 * 8   4/18/08 4:03p vsilyaev
420 * PR 41868: Added security API to playpump and recpump
421 *
422 * 7   4/17/08 9:31a erickson
423 * PR39994: remove param
424 *
425 * 6   4/10/08 2:40p erickson
426 * PR41557: enable ES packetization for all chips
427 *
428 * 5   4/9/08 1:09p jgarrett
429 * PR 41557: Fixing GetDefaultOpenPidChannelSettings
430 *
431 * 4   2/28/08 9:44p vsilyaev
432 * PR 40103: Used NEXUS_TaskCallback functions for API callbacks
433 *
434 * 3   2/26/08 10:53a erickson
435 * PR34925: default playRate
436 *
437 * 2   1/21/08 10:42a gmullen
438 * PR38854: Set BPVRlib channelNum to playpump instance.
439 *
440 * 1   1/18/08 2:20p jgarrett
441 * PR 38808: Merging to main branch
442 *
443 **************************************************************************/
444#include "nexus_transport_module.h"
445#include "nexus_playpump_impl.h"
446#include "bchp_int_id_xpt_pb0.h"
447#include "bchp_int_id_xpt_pb1.h"
448#if NEXUS_NUM_PLAYPUMPS > 2
449#include "bchp_int_id_xpt_pb2.h"
450#endif
451#if NEXUS_NUM_PLAYPUMPS > 3
452#include "bchp_int_id_xpt_pb3.h"
453#endif
454#if NEXUS_NUM_PLAYPUMPS > 4
455#include "bchp_int_id_xpt_pb4.h"
456#endif
457#if NEXUS_NUM_PLAYPUMPS > 5
458#include "bchp_int_id_xpt_pb5.h"
459#endif
460#if NEXUS_NUM_PLAYPUMPS > 6
461#include "bchp_int_id_xpt_pb6.h"
462#endif
463#if NEXUS_NUM_PLAYPUMPS > 7
464#include "bchp_int_id_xpt_pb7.h"
465#endif
466#if NEXUS_HAS_SECURITY
467#include "nexus_security.h"
468#endif
469#include "priv/nexus_timebase_priv.h"
470#include "nexus_class_verification.h"
471
472BDBG_MODULE(nexus_playpump);
473
474BDBG_OBJECT_ID(NEXUS_Playpump);
475
476#define NEXUS_P_PACKETIZER_BASE (0x100)
477
478static BERR_Code NEXUS_Playpump_P_SetParserBand(NEXUS_PlaypumpHandle p, const NEXUS_PlaypumpSettings *pSettings);
479static void NEXUS_Playpump_P_InstallRangeErrIntHandler(NEXUS_PlaypumpHandle p);
480static void NEXUS_Playpump_P_UninstallRangeErrIntHandler(NEXUS_PlaypumpHandle p);
481static NEXUS_Error NEXUS_Playpump_P_SetInterrupts(NEXUS_PlaypumpHandle p, const NEXUS_PlaypumpSettings *pSettings);
482
483void NEXUS_Playpump_GetDefaultOpenSettings(NEXUS_PlaypumpOpenSettings *pSettings)
484{
485    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
486    pSettings->streamMuxCompatible = false;
487    pSettings->fifoSize = B_PVR_PLAYBACK_BUFFER;
488    pSettings->alignment = 12; /* 2^12 = 4096  (I/O block size) alignment */
489    pSettings->numDescriptors = NEXUS_NUM_PLAYBACK_DESC;
490}
491void
492NEXUS_Playpump_GetDefaultSettings(NEXUS_PlaypumpSettings *pSettings)
493{
494    BDBG_ASSERT(pSettings);
495    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
496#if NEXUS_NUM_DMA_CHANNELS
497    pSettings->securityDmaDataFormat = NEXUS_DmaDataFormat_eMpeg;
498#endif
499    pSettings->transportType = NEXUS_TransportType_eTs;
500    pSettings->originalTransportType = NEXUS_TransportType_eUnknown;
501    pSettings->timestamp.type = NEXUS_TransportTimestampType_eNone;
502    pSettings->timestamp.timebase = NEXUS_Timebase_eInvalid;
503    pSettings->timestamp.pacingMaxError = 1024; /* HW reset value */
504    pSettings->timestamp.parityCheckDisable = false; /* HW reset value */
505    pSettings->mode = NEXUS_PlaypumpMode_eFifo;
506    pSettings->playRate = NEXUS_NORMAL_PLAY_SPEED;
507    pSettings->allPass = false;
508    pSettings->acceptNullPackets = false;
509    pSettings->maxDataRate = 108000000;
510    NEXUS_CallbackDesc_Init(&pSettings->dataCallback);
511    NEXUS_CallbackDesc_Init(&pSettings->errorCallback);
512    return;
513}
514
515NEXUS_PlaypumpHandle
516NEXUS_Playpump_Open(unsigned index, const NEXUS_PlaypumpOpenSettings *pSettings)
517{
518#if NEXUS_NUM_PLAYPUMPS
519    NEXUS_PlaypumpHandle p;
520    BXPT_Playback_ChannelSettings play_cfg;
521    BERR_Code rc;
522    BPVRlib_Feed_Settings feed_cfg;
523    NEXUS_PlaypumpOpenSettings defaultSettings;
524    NEXUS_HeapHandle heap;
525
526    if (!pSettings) {
527        NEXUS_Playpump_GetDefaultOpenSettings(&defaultSettings);
528        pSettings = &defaultSettings;
529    }
530    if (index == NEXUS_ANY_ID) {
531        unsigned i;
532        for (i=0;i<NEXUS_NUM_PLAYPUMPS;i++) {
533            if (!pTransport->playpump[i].playpump) {
534                index = i;
535                break;
536            }
537        }
538        if (i == NEXUS_NUM_PLAYPUMPS) {
539            rc = BERR_TRACE(NEXUS_NOT_AVAILABLE);
540            BDBG_ERR(("no playpump not available"));
541            return NULL;
542        }
543    }
544
545    if (index >= NEXUS_NUM_PLAYPUMPS) {
546        rc = BERR_TRACE(BERR_INVALID_PARAMETER);
547        BDBG_ERR(("playpump[%d] not available", index));
548        return NULL;
549    }
550
551    if (pTransport->playpump[index].playpump) {
552        rc = BERR_TRACE(BERR_INVALID_PARAMETER);
553        BDBG_ERR(("playpump[%d] already open", index));
554        return NULL;
555    }
556    pTransport->playpump[index].playpump = p = BKNI_Malloc(sizeof(*p));
557    if (!p) {
558        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
559        return NULL;
560    }
561    BKNI_Memset(p, 0, sizeof(*p));
562    BDBG_OBJECT_SET(p, NEXUS_Playpump);
563
564    p->index = index;
565    p->openSettings = *pSettings;
566    p->consumerStarted = false;
567    NEXUS_Playpump_GetDefaultSettings(&p->settings);
568    p->settings.transportType = NEXUS_TransportType_eTs;
569    p->settings.timestamp.type = NEXUS_TransportTimestampType_eNone;
570    p->settings.timestamp.pacing = false;
571    p->settings.playRate = NEXUS_NORMAL_PLAY_SPEED;
572    p->dataCallback = NEXUS_TaskCallback_Create(p, NULL);
573    if(!p->dataCallback) {
574        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
575        goto error;
576    }
577    p->errorCallback = NEXUS_TaskCallback_Create(p, NULL);
578    if(!p->errorCallback) {
579        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
580        goto error;
581    }
582    p->ccErrorCallback = NEXUS_IsrCallback_Create(p, NULL);
583    if(!p->ccErrorCallback) {
584        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
585        goto error;
586    }
587    p->teiErrorCallback = NEXUS_IsrCallback_Create(p, NULL);
588    if(!p->teiErrorCallback) {
589        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
590        goto error;
591    }
592    NEXUS_CallbackDesc_Init(&p->settings.dataCallback);
593    NEXUS_CallbackDesc_Init(&p->settings.errorCallback);
594    b_pid_map_init(&p->packetizer_map, NEXUS_P_PACKETIZER_BASE);
595
596    BLST_S_INIT(&p->pid_list);
597
598    p->item_mem = BKNI_Malloc(sizeof(*p->item_mem)*pSettings->numDescriptors);
599    if(p->item_mem==NULL) {
600        rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
601        goto error;
602    }
603
604    heap = NEXUS_P_DefaultHeap(pSettings->heap);
605    if (!heap) {
606        heap = g_pCoreHandles->nexusHeap[pTransport->settings.mainHeapIndex];
607    }
608    /* some playpump operations require driver CPU accessible to the playback fifo */
609    if (!NEXUS_P_CpuAccessibleHeap(heap)) {
610        rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
611        goto error;
612    }
613    p->heap = NEXUS_Heap_GetMemHandle(heap);
614
615    /* fifoSize == 0 is valid for scatter/gather-only mode */
616    if (pSettings->fifoSize) {
617        p->buf_noncached = BMEM_AllocAligned(p->heap, pSettings->fifoSize, pSettings->alignment, 0);
618        if (!p->buf_noncached) {
619            rc = BERR_TRACE(NEXUS_OUT_OF_DEVICE_MEMORY);
620            goto error;
621        }
622        rc = BMEM_Heap_ConvertAddressToCached(p->heap, p->buf_noncached, &p->buf); /* map memory to the cached region */
623        if (rc) {rc=BERR_TRACE(rc); goto error;}
624    }
625    BDBG_MSG(("alloc buffer %p %d", p->buf, pSettings->fifoSize));
626
627    heap = NEXUS_P_DefaultBoundsHeap(pSettings->boundsHeap);
628    if (heap) {
629        BMEM_HeapInfo heapInfo;
630        BMEM_Heap_Handle boundsHeap = NEXUS_Heap_GetMemHandle(heap);
631        BMEM_Heap_GetInfo(boundsHeap, &heapInfo);
632        p->boundsHeapSize = heapInfo.zSize;
633        rc = BMEM_Heap_ConvertAddressToCached(boundsHeap, heapInfo.pvAddress, &p->boundsHeapAddr);
634        if (rc) {
635            rc = BERR_TRACE(rc);
636            p->boundsHeapAddr = 0;
637            p->boundsHeapSize = 0;
638        }
639    }
640
641    b_playpump_p_reset(p);
642
643    rc = BXPT_Playback_GetChannelDefaultSettings(pTransport->xpt, index, &play_cfg);
644    if (rc) {rc=BERR_TRACE(rc);goto error;}
645
646#if NEXUS_HAS_LEGACY_XPT
647    play_cfg.AlwaysResumeFromLastDescriptor = true;
648#endif
649
650    rc = BXPT_Playback_OpenChannel(pTransport->xpt, &p->xpt_play, index, &play_cfg);
651    if (rc) {rc=BERR_TRACE(rc);goto error;}
652
653    rc = NEXUS_Playpump_P_SetParserBand(p, &p->settings);
654    if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc);goto error;}
655
656    BPVRlib_Feed_GetDefaultSettings(&feed_cfg);
657    feed_cfg.xptHandle = pTransport->xpt;
658    feed_cfg.xptPlayHandle = p->xpt_play;
659    feed_cfg.heap = p->heap;
660    feed_cfg.intHandle = g_pCoreHandles->bint;
661    feed_cfg.numDesc = 32;
662    feed_cfg.applicationCnxt = p;
663    feed_cfg.useExtndedDesc = pSettings->streamMuxCompatible;
664    feed_cfg.descAvaliable_isr = NEXUS_P_Playpump_DescAvail_isr;
665    rc = BPVRlib_Feed_Open(&p->play_feed, &feed_cfg);
666    if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc);goto error;}
667
668    rc = BKNI_CreateEvent(&p->descEvent);
669    if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc);goto error;}
670
671#if B_HAS_PLAYPUMP_IP
672    {
673        rc = b_playpump_ip_open(&p->ip, p, open_params);
674        if (rc) { rc = BERR_TRACE(rc);goto error; }
675    }
676#endif
677
678    /* init vob remap state */
679    p->vob_remap_state.codec = NEXUS_AudioCodec_eMpeg;
680    p->vob_remap_state.track = 0;
681
682    p->crypto = b_pump_crypto_create(p);
683#if 0 /* if security module not connected, NULL is normal */
684    if(!p->crypto) {
685        rc = BERR_TRACE(NEXUS_UNKNOWN);
686        goto error;
687    }
688#endif
689
690#if B_HAS_MEDIA
691    p->use_media = false;
692    p->demux = b_pump_demux_create(p);
693    if(!p->demux) {
694        rc = BERR_TRACE(NEXUS_UNKNOWN);
695        goto error;
696    }
697#endif
698
699    return p;
700error:
701    if (p) {
702        if (p->crypto) {
703            b_pump_crypto_destroy(p->crypto);
704        }
705        if (p->play_feed) {
706            BPVRlib_Feed_Close(p->play_feed);
707        }
708        if (p->descEvent) {
709            BKNI_DestroyEvent(p->descEvent);
710        }
711        if (p->xpt_play) {
712            BXPT_Playback_CloseChannel(p->xpt_play);
713        }
714        if (p->buf_noncached) {
715            BMEM_Free(p->heap, p->buf_noncached);
716        }
717        if(p->item_mem) {
718            BKNI_Free(p->item_mem);
719        }
720        if(p->errorCallback) {
721            NEXUS_TaskCallback_Destroy(p->errorCallback);
722        }
723        if(p->ccErrorCallback) {
724            NEXUS_IsrCallback_Destroy(p->ccErrorCallback);
725        }
726        if(p->teiErrorCallback) {
727            NEXUS_IsrCallback_Destroy(p->teiErrorCallback);
728        }
729        if(p->dataCallback) {
730            NEXUS_TaskCallback_Destroy(p->dataCallback);
731        }
732        BKNI_Free(p);
733        pTransport->playpump[index].playpump = NULL;
734    }
735#else
736    BSTD_UNUSED(index);
737    BSTD_UNUSED(pSettings);
738#endif
739    return NULL;
740}
741
742void NEXUS_Playpump_Close(NEXUS_PlaypumpHandle p)
743{
744    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
745    if (p->state.running) {
746        NEXUS_Playpump_Stop(p);
747    }
748#if B_HAS_PLAYPUMP_IP
749    b_playpump_ip_close(&p->ip);
750#endif
751    if (p->crypto) {
752        b_pump_crypto_destroy(p->crypto);
753    }
754#if B_HAS_MEDIA
755    b_pump_demux_destroy(p->demux);
756#endif
757    p->state.packetizer = b_play_packetizer_none;
758
759    /* force the destroying of the xpt interrupt */
760    p->settings.ccError.callback = NULL;
761    p->settings.teiError.callback = NULL;
762    NEXUS_Playpump_P_SetInterrupts(p, &p->settings);
763
764    BPVRlib_Feed_Close(p->play_feed);
765    BKNI_DestroyEvent(p->descEvent);
766    BXPT_Playback_CloseChannel(p->xpt_play);
767    if (p->buf_noncached) {
768        BMEM_Free(p->heap, p->buf_noncached);
769    }
770    BKNI_Free(p->item_mem);
771    p->xpt_play = NULL;
772    p->play_feed = NULL;
773#if NEXUS_NUM_PLAYPUMPS
774    pTransport->playpump[p->index].playpump = NULL;
775#endif
776    NEXUS_IsrCallback_Destroy(p->ccErrorCallback);
777    NEXUS_IsrCallback_Destroy(p->teiErrorCallback);
778    NEXUS_TaskCallback_Destroy(p->errorCallback);
779    NEXUS_TaskCallback_Destroy(p->dataCallback);
780    BDBG_OBJECT_DESTROY(p, NEXUS_Playpump);
781    BKNI_Free(p);
782}
783
784void NEXUS_Playpump_GetSettings(NEXUS_PlaypumpHandle p, NEXUS_PlaypumpSettings *pSettings)
785{
786    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
787    BDBG_ASSERT(pSettings);
788    *pSettings = p->settings;
789    return;
790}
791
792static BERR_Code
793NEXUS_Playpump_P_SetParserBand(NEXUS_PlaypumpHandle p, const NEXUS_PlaypumpSettings *pSettings)
794{
795    BXPT_Playback_ParserConfig parserConfig;
796    BERR_Code rc;
797
798    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
799    BDBG_ASSERT(p->xpt_play);
800
801#if B_HAS_DSS
802    rc = BXPT_DirecTvPlayback_SetParserBandMode( p->xpt_play, NEXUS_IS_DSS_MODE(pSettings->transportType)?
803        BXPT_ParserMode_eDirecTv : BXPT_ParserMode_eMpeg); /* XXX this shall precced SetParserConfig, since it resets parser configuration */
804    if (rc) return BERR_TRACE(rc);
805#endif
806
807    rc = BXPT_Playback_GetParserConfig(p->xpt_play, &parserConfig);
808    if (rc) return BERR_TRACE(rc);
809    /* for playback, we should just let all data through. if the stream is good, there's no harm.
810    if the stream is bad, the decoders must handle this anyway. */
811#if NEXUS_PARSER_BAND_CC_CHECK
812    parserConfig.ContCountIgnore = !pSettings->continuityCountEnabled;
813#else
814    if(pSettings->continuityCountEnabled != p->settings.continuityCountEnabled && BLST_S_FIRST(&p->pid_list)!=NULL) {
815        BDBG_WRN(("%#lx:continuityCountEnabled wouldn't get applied to aleady opened pids", (unsigned long)p));
816    }
817#endif
818    parserConfig.ErrorInputIgnore = (pSettings->teiError.callback == NULL); /* if we want these errors, then transport cannot ignore */
819    parserConfig.AcceptAdapt00 = true;
820    parserConfig.AllPass = pSettings->allPass;
821    parserConfig.AcceptNulls = pSettings->acceptNullPackets;
822
823#if BXPT_HAS_PCR_PACING
824    /* enable PARSER_FORCE_RESTAMP in pcr-pacing mode */
825    parserConfig.ForceRestamping = (pSettings->timestamp.pacing && pSettings->timestamp.pcrPacingPid);
826#endif
827    if (pSettings->timestamp.forceRestamping==true) {
828        parserConfig.ForceRestamping = true;
829    }
830
831    parserConfig.UsePcrTimeBase = true; /* eInvalid now means get the default timebase and track it */
832    if (parserConfig.UsePcrTimeBase) {
833        NEXUS_TimebaseHandle timebase = NEXUS_Timebase_Resolve_priv(pSettings->timestamp.timebase);
834        if (timebase)
835        {
836            parserConfig.WhichPcrToUse = timebase->hwIndex;
837        }
838        else
839        {
840            return BERR_TRACE(NEXUS_INVALID_PARAMETER);
841        }
842    }
843    rc = BXPT_Playback_SetParserConfig(p->xpt_play, &parserConfig);
844    if (rc) return BERR_TRACE(rc);
845
846    rc = BXPT_Playback_SetBitRate(p->xpt_play, pSettings->maxDataRate);
847    if (rc) return BERR_TRACE(rc);
848
849    return 0;
850}
851
852
853NEXUS_Error
854NEXUS_Playpump_SetSettings(NEXUS_PlaypumpHandle p, const NEXUS_PlaypumpSettings *pSettings)
855{
856    NEXUS_Error rc;
857
858    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
859    BDBG_ASSERT(pSettings);
860
861    if (pSettings->playRate == 0) {
862        /* playRate == 0 is not pause. It must be non-zero. */
863        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
864    }
865
866    if(p->state.running && (
867                p->settings.transportType != pSettings->transportType ||
868                p->settings.timestamp.type != pSettings->timestamp.type ||
869                p->settings.timestamp.pacing != pSettings->timestamp.pacing ||
870#if NEXUS_NUM_DMA_CHANNELS
871                p->settings.securityDma != pSettings->securityDma ||
872#endif
873#if NEXUS_HAS_SECURITY
874                p->settings.securityContext != pSettings->securityContext ||
875#endif
876                p->settings.mode != pSettings->mode
877                )) {
878        BDBG_WRN(("NEXUS_Playpump_SetSettings: %lx can't change settings when started", (unsigned long)p));
879        rc = BERR_TRACE(BERR_NOT_SUPPORTED);
880        goto err_running;
881    }
882
883#if NEXUS_NUM_DMA_CHANNELS
884    if (pSettings->securityDma && !pTransport->settings.dma) {
885        BDBG_ERR(("Transport module does not have dma module handle."));
886        return BERR_TRACE(BERR_NOT_SUPPORTED);
887    }
888#endif
889#if NEXUS_HAS_SECURITY
890    if (pSettings->securityContext && !pTransport->settings.security) {
891        BDBG_ERR(("Transport module does not have security module handle."));
892        return BERR_TRACE(BERR_NOT_SUPPORTED);
893    }
894#endif
895
896    if (pSettings->timestamp.pacingMaxError != p->settings.timestamp.pacingMaxError) {
897        rc = BXPT_Playback_SetPacingErrorBound(p->xpt_play, pSettings->timestamp.pacingMaxError);
898        if (rc) return BERR_TRACE(rc);
899    }
900
901    if (pSettings->timestamp.timebase != p->settings.timestamp.timebase) {
902        BXPT_Playback_ChannelSettings cfg;
903
904        rc = BXPT_Playback_GetChannelSettings(p->xpt_play, &cfg);
905        if (rc) return BERR_TRACE(rc);
906
907        cfg.UsePcrTimeBase = true; /* eInvalid now means get the default timebase and track it */
908        if (cfg.UsePcrTimeBase) {
909            NEXUS_TimebaseHandle timebase = NEXUS_Timebase_Resolve_priv(pSettings->timestamp.timebase);
910            if (timebase)
911            {
912                cfg.WhichPcrToUse = timebase->hwIndex;
913            }
914            else
915            {
916                return BERR_TRACE(NEXUS_INVALID_PARAMETER);
917            }
918        }
919
920        rc = BXPT_Playback_SetChannelSettings(p->xpt_play, &cfg);
921        if (rc) return BERR_TRACE(rc);
922    }
923
924    if(pSettings->transportType != p->settings.transportType) {
925        if(BLST_S_FIRST(&p->pid_list)!=NULL) {
926            BDBG_WRN(("NEXUS_Playpump_SetSettings: %lx can't change settings when PIDs are attached", (unsigned long)p));
927            rc = BERR_TRACE(BERR_NOT_SUPPORTED);
928            goto err_attached;
929        }
930#if B_HAS_MEDIA
931        rc = b_pump_demux_set_stream_type(p->demux, pSettings->transportType, &p->use_media);
932        if(rc!=NEXUS_SUCCESS) { rc=BERR_TRACE(rc); goto err_media;}
933        BDBG_MSG(("NEXUS_Playpump_SetSettings: %s of stream type %u", p->use_media?"media preprocessing":"native processsing", pSettings->transportType));
934
935        if(!p->use_media) {
936            bool supported;
937
938            if (p->crypto) {
939                rc = b_pump_crypto_set_stream_type(p->crypto, pSettings->transportType, &supported);
940                if(rc!=NEXUS_SUCCESS) { rc=BERR_TRACE(rc); goto err_crypto;}
941            }
942        }
943#endif
944    }
945
946    rc = NEXUS_Playpump_P_SetParserBand(p, pSettings);
947    if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc);goto err_parser_band;}
948
949#if B_HAS_MEDIA
950    if(p->settings.playRate != pSettings->playRate) {
951        if (p->state.packetizer==b_play_packetizer_media) {
952            b_pump_demux_set_rate(p->demux, pSettings->playRate);
953        }
954    }
955#endif
956    p->settings = *pSettings;
957    NEXUS_TaskCallback_Set(p->dataCallback, &p->settings.dataCallback);
958    NEXUS_TaskCallback_Set(p->errorCallback, &p->settings.errorCallback);
959    NEXUS_Playpump_P_SetInterrupts(p, &p->settings);
960
961#if B_HAS_MEDIA
962err_crypto:
963err_media:
964#endif
965err_parser_band:
966err_running:
967err_attached:
968    return rc;
969}
970
971static NEXUS_Error NEXUS_Playpump_P_StartPid(NEXUS_PlaypumpHandle p, NEXUS_P_PlaypumpPidChannel *play_pid)
972{
973    NEXUS_Error rc;
974
975#if NEXUS_HAS_SECURITY && (NEXUS_NUM_DMA_CHANNELS==0)
976    if (p->settings.securityContext) {
977        rc = NEXUS_Security_AddPidChannelToKeySlot(p->settings.securityContext, play_pid->pid_channel->status.pidChannelIndex);
978        if (rc) return BERR_TRACE(rc);
979    }
980#endif
981
982    /* activate packetizer to all pids that needs packetizer */
983    if(play_pid->packetizer.enable) {
984        rc = BXPT_Playback_PacketizeStream(p->xpt_play, play_pid->packetizer.context, &play_pid->packetizer.cfg, true);
985        if (rc) return BERR_TRACE(rc);
986        play_pid->packetizer.active = true;
987    }
988
989    return 0;
990}
991
992static void NEXUS_Playpump_P_StopPid(NEXUS_PlaypumpHandle p, NEXUS_P_PlaypumpPidChannel *play_pid)
993{
994    NEXUS_Error rc;
995
996#if NEXUS_HAS_SECURITY && (NEXUS_NUM_DMA_CHANNELS==0)
997    if (p->settings.securityContext) {
998        (void)NEXUS_Security_RemovePidChannelFromKeySlot(p->settings.securityContext, play_pid->pid_channel->status.pidChannelIndex);
999    }
1000#endif
1001
1002    if(play_pid->packetizer.enable) {
1003        rc = BXPT_Playback_PacketizeStream(p->xpt_play, play_pid->packetizer.context, &play_pid->packetizer.cfg, false);
1004        if (rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); }
1005        play_pid->packetizer.active = false;
1006    }
1007}
1008
1009static NEXUS_Error NEXUS_Playpump_Start_priv(NEXUS_PlaypumpHandle p, bool muxInput)
1010{
1011    BERR_Code rc;
1012    BXPT_Playback_ChannelSettings cfg;
1013    NEXUS_TransportType transportType;
1014    NEXUS_P_PlaypumpPidChannel *play_pid;
1015
1016    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1017
1018    if(NEXUS_GetEnv("profile_playpump")) {
1019        NEXUS_Profile_Start();
1020    }
1021
1022    if (p->state.running) { rc = BERR_TRACE(NEXUS_NOT_SUPPORTED); goto err_state; }
1023
1024    /* If we're in allPass, verify that there is one, and only one, PID channel on the playback. Check that the PID
1025       channel used is correct too. */
1026    if (p->settings.allPass)
1027    {
1028        unsigned AllPassPidChannel;
1029        NEXUS_P_PlaypumpPidChannel *play_pid;
1030
1031        unsigned ChannelCount = 0;
1032        bool FoundValidChannel = false;
1033
1034        NEXUS_Playpump_GetAllPassPidChannelIndex( p, &AllPassPidChannel );
1035        for(play_pid=BLST_S_FIRST(&p->pid_list); play_pid; play_pid=BLST_S_NEXT(play_pid, link)) 
1036        {
1037            ChannelCount++;
1038            if(play_pid->pid_channel->status.pidChannelIndex == AllPassPidChannel) 
1039            {
1040                FoundValidChannel = true;
1041            }
1042        }
1043
1044        if( !ChannelCount || 1 < ChannelCount )
1045        {
1046            BDBG_ERR(( "Only 1 PID channel is supported in allPass mode." ));
1047            rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1048            goto error;
1049        }
1050
1051        if( !FoundValidChannel )
1052        {
1053            BDBG_ERR(( "Incorrect PID channel used for allPass. See NEXUS_Playpump_GetAllPassPidChannelIndex()." ));
1054            rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1055            goto error;
1056        }
1057    }
1058
1059    BKNI_Memset(&p->state, 0, sizeof(p->state)); /* wipe-out all temporary state */
1060    BKNI_Memset(&cfg, 0, sizeof(cfg));
1061
1062    NEXUS_Transport_P_IncPowerDown(true);
1063
1064    rc = NEXUS_Playpump_P_SetParserBand(p, &p->settings);
1065    if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc);goto err_parser_band;}
1066
1067    transportType = p->settings.transportType;
1068#if B_HAS_MEDIA
1069    p->state.packetizer = p->use_media ? b_play_packetizer_media:b_play_packetizer_none;
1070    if (p->state.packetizer==b_play_packetizer_media) {
1071        transportType = NEXUS_TransportType_eMpeg2Pes;
1072    } else
1073#endif
1074#if NEXUS_NUM_DMA_CHANNELS
1075    if (p->settings.securityDma && p->crypto) {
1076        p->state.packetizer = b_play_packetizer_crypto;
1077    }
1078#endif
1079
1080    rc = BXPT_Playback_GetChannelSettings(p->xpt_play, &cfg);
1081    if (rc) {rc=BERR_TRACE(rc); goto error;}
1082
1083#if NEXUS_HAS_LEGACY_XPT
1084    cfg.AlwaysResumeFromLastDescriptor = true;
1085#endif
1086#if B_HAS_NATIVE_MPEG1
1087    /* initialize to the MPEG2 Program Stream Mode */
1088    cfg.PsMode = BXPT_Playback_PS_Mode_MPEG2;
1089    cfg.PackHdrConfig = BXPT_Playback_PackHdr_Drop;
1090#endif
1091
1092#if B_PACKETIZE_HSX
1093    if (!(transportType == NEXUS_TransportType_eTs || NEXUS_IS_DSS_MODE(transportType))) {
1094        cfg.SyncMode = BXPT_PB_SYNC_MPEG_BLIND; /* TS Blind */
1095        cfg.PacketLength = 184;
1096    } else
1097#endif
1098    switch(transportType) {
1099    case NEXUS_TransportType_eEs:
1100        cfg.SyncMode = BXPT_PB_SYNC_MPEG_BLIND; /* TS Blind */
1101        cfg.PacketLength = 184;
1102        break;
1103#if B_HAS_NATIVE_MPEG1
1104    case NEXUS_TransportType_eMpeg1Ps:
1105        cfg.PsMode = BXPT_Playback_PS_Mode_MPEG1;
1106        cfg.PackHdrConfig = BXPT_Playback_PackHdr_Drop;
1107        /* fallthrough */
1108#endif
1109    case NEXUS_TransportType_eVob:
1110#if !BXPT_HAS_PID_CHANNEL_PES_FILTERING
1111        cfg.PackHdrConfig = BXPT_Playback_PackHdr_Payload_Insert;
1112        cfg.PacketLength = 0x80;
1113        cfg.SyncMode = BXPT_PB_SYNC_MPEG_BLIND;
1114    break;
1115#endif
1116        /* fall through */
1117
1118    case NEXUS_TransportType_eMpeg2Pes:
1119        cfg.SyncMode = BXPT_PB_SYNC_PES; /* TS PES */
1120        break;
1121
1122    case NEXUS_TransportType_eTs:
1123        cfg.PacketLength = 188;
1124        cfg.SyncMode = BXPT_PB_SYNC_MPEG; /* TS mode. This allows HW to search for the 0x47 sync byte. */
1125        break;
1126#if B_HAS_DSS
1127    case NEXUS_TransportType_eDssPes:
1128    case NEXUS_TransportType_eDssEs:
1129        cfg.PacketLength = 130;
1130        cfg.SyncMode = BXPT_PB_SYNC_MPEG_BLIND; /* direct TV mode. Use MPEG blind-sync, per DVT's suggestion. PR 42365 */
1131        break;
1132#endif
1133    default:
1134        rc = BERR_TRACE(NEXUS_UNKNOWN);
1135        goto error;
1136    }
1137
1138    if (p->settings.blindSync) {
1139        cfg.SyncMode = BXPT_PB_SYNC_MPEG_BLIND;
1140    }
1141
1142    switch (p->settings.timestamp.type) {
1143    case NEXUS_TransportTimestampType_eNone:
1144        cfg.TimestampEn = false;
1145        break;
1146    case NEXUS_TransportTimestampType_e30_2U_Mod300:
1147        cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Mod300;
1148        cfg.TimestampEn = true;
1149        #if BXPT_HAS_32BIT_PB_TIMESTAMPS
1150        cfg.Use32BitTimestamps = false;
1151        #endif
1152        break;
1153    case NEXUS_TransportTimestampType_e30_2U_Binary:
1154        cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Binary;
1155        cfg.TimestampEn = true;
1156        #if BXPT_HAS_32BIT_PB_TIMESTAMPS
1157        cfg.Use32BitTimestamps = false;
1158        #endif
1159        break;
1160    #if BXPT_HAS_32BIT_PB_TIMESTAMPS
1161    case NEXUS_TransportTimestampType_e32_Mod300:
1162        cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Mod300;
1163        cfg.TimestampEn = true;
1164        cfg.Use32BitTimestamps = true;
1165        break;
1166    case NEXUS_TransportTimestampType_e32_Binary:
1167        cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Binary;
1168        cfg.TimestampEn = true;
1169        cfg.Use32BitTimestamps = true;
1170/* TODO: enable this when needed
1171    case NEXUS_TransportTimestampType_e28_4P_Mod300:   
1172        rec_cfg.TimestampMode = BXPT_TimestampMode_e28_4P_Mod300;
1173        rec_cfg.TimestampEn = true;
1174        rec_cfg.Use32BitTimestamps = true;
1175        break;
1176*/       
1177        break;
1178    #endif
1179    default:
1180        rc = BERR_TRACE(NEXUS_NOT_SUPPORTED);
1181        goto error;
1182    }
1183
1184    if (p->settings.timestamp.pcrPacingPid && p->settings.timestamp.pacing) {
1185#if BXPT_HAS_PCR_PACING
1186        cfg.PcrPacingPid = p->settings.timestamp.pcrPacingPid;
1187        cfg.PcrBasedPacing = true;
1188#else
1189        rc = BERR_TRACE(NEXUS_NOT_SUPPORTED);
1190        goto error;
1191#endif
1192    }
1193
1194    cfg.ResetPacing = p->settings.timestamp.resetPacing;
1195    cfg.DisableTimestampParityCheck = p->settings.timestamp.parityCheckDisable;
1196    cfg.UsePcrTimeBase = true; /* eInvalid now means get the default timebase and track it */
1197    if (cfg.UsePcrTimeBase) {
1198        NEXUS_TimebaseHandle timebase = NEXUS_Timebase_Resolve_priv(p->settings.timestamp.timebase);
1199        if (timebase)
1200        {
1201            cfg.WhichPcrToUse = timebase->hwIndex;
1202        }
1203        else
1204        {
1205            return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1206        }
1207    }
1208    cfg.PacingOffsetAdjustDisable = p->settings.timestamp.pacingOffsetAdjustDisable;
1209
1210#if BXPT_HAS_TSMUX
1211    if(muxInput) {
1212        cfg.PesBasedPacing = true;
1213        cfg.Use8WordDesc = true;
1214        cfg.PesBasedPacing = true;
1215        cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Binary;
1216        cfg.Use32BitTimestamps = true;
1217        cfg.TimestampEn = false;
1218    } else {
1219        cfg.PesBasedPacing = false;
1220        cfg.Use8WordDesc = false;
1221    }
1222#else
1223    BSTD_UNUSED(muxInput);
1224#endif
1225    rc = BXPT_Playback_SetChannelSettings(p->xpt_play, &cfg);
1226    if (rc) {rc=BERR_TRACE(rc);goto error;}
1227
1228#if B_HAS_VBI
1229    rc = bstream_p_vbi_open(&p->stream);
1230    if (rc) goto error;
1231#endif
1232
1233    if (p->settings.timestamp.pacing) {
1234        rc = BXPT_Playback_ConfigPacing(p->xpt_play, BXPT_PacingControl_eStart);
1235        if (rc) goto error;
1236        p->state.pacing = true;
1237
1238        NEXUS_Playpump_P_InstallRangeErrIntHandler(p);
1239    }
1240
1241    for(play_pid=BLST_S_FIRST(&p->pid_list);play_pid!=NULL;play_pid=BLST_S_NEXT(play_pid, link)) {
1242        rc = NEXUS_Playpump_P_StartPid(p, play_pid);
1243        if (rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto error; }
1244    }
1245
1246#if B_HAS_MEDIA
1247    if (p->state.packetizer==b_play_packetizer_media) {
1248        rc = b_pump_demux_start(p->demux);
1249        if(rc!=NEXUS_SUCCESS) {rc=BERR_TRACE(rc);goto error;}
1250    } else
1251#endif
1252    if (p->state.packetizer==b_play_packetizer_crypto) {
1253        rc = b_pump_crypto_start(p->crypto);
1254        if(rc!=NEXUS_SUCCESS) {rc=BERR_TRACE(rc);goto error;}
1255    } else {
1256        rc = BPVRlib_Feed_Start(p->play_feed);
1257        if (rc) {rc=BERR_TRACE(rc);goto error;}
1258    }
1259
1260    /* pause playback until first consumer (decode or record) is started. this prevent data from being lost
1261    if any amount of time between playback start and rave configuration (which is done at decode start). */
1262    if(!p->consumerStarted) { /* 't pause on Start */
1263        rc = BXPT_Playback_Pause(p->xpt_play);
1264        if (rc) {rc=BERR_TRACE(rc);goto error_pause;}
1265    }
1266
1267    /* We may have a left over event, and we want to ensure that 1 interrupt
1268    always means 1 free descriptor in b_playpump_p_xpt_event */
1269    BKNI_ResetEvent(p->descEvent);
1270
1271    p->playEventHandle = NEXUS_RegisterEvent(p->descEvent, b_playpump_p_xpt_event, p);
1272    if (!p->playEventHandle) {rc=BERR_TRACE(NEXUS_UNKNOWN); goto error_started;}
1273
1274    /* Set run state because calling first read */
1275    p->state.running = true;
1276    p->state.muxInput = muxInput;
1277
1278    if(!muxInput) {
1279        /* Request the first async read, which kickstarts the read cycle. */
1280        b_playpump_p_do_read_callback(p);
1281
1282        p->throttle_timer = NEXUS_ScheduleTimer(B_THROTTLE_TIMEOUT, b_playpump_p_throttle_timer, p);  /* schedulle timer after 30 ms */
1283    }
1284
1285    return 0;
1286
1287error_pause:
1288error_started:
1289#if B_HAS_MEDIA
1290    if (p->state.packetizer==b_play_packetizer_media) {
1291        b_pump_demux_stop(p->demux);
1292    } else
1293#endif
1294    if (p->state.packetizer==b_play_packetizer_crypto) {
1295        b_pump_crypto_stop(p->crypto);
1296    } else {
1297        BPVRlib_Feed_Stop(p->play_feed);
1298    }
1299    if (p->state.pacing) {
1300        NEXUS_Playpump_P_UninstallRangeErrIntHandler(p);
1301
1302        rc = BXPT_Playback_ConfigPacing(p->xpt_play,BXPT_PacingControl_eStop);
1303        if (rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc);}
1304    }
1305err_parser_band:
1306    NEXUS_Transport_P_IncPowerDown(false);
1307err_state:
1308error:
1309    BDBG_ASSERT(rc);
1310    return rc;
1311}
1312
1313NEXUS_Error NEXUS_Playpump_Start(NEXUS_PlaypumpHandle p)
1314{
1315    return NEXUS_Playpump_Start_priv(p, false);
1316}
1317
1318NEXUS_Error NEXUS_Playpump_StartMuxInput_priv(NEXUS_PlaypumpHandle playpump)
1319{
1320    NEXUS_ASSERT_MODULE();
1321    BDBG_OBJECT_ASSERT(playpump, NEXUS_Playpump);
1322    return NEXUS_Playpump_Start_priv(playpump, true);
1323}
1324
1325
1326void NEXUS_Playpump_Stop(NEXUS_PlaypumpHandle p)
1327{
1328    BERR_Code rc;
1329    NEXUS_P_PlaypumpPidChannel *play_pid;
1330
1331    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1332    if(!p->state.running) {
1333        BDBG_WRN(("NEXUS_Playpump_Stop: %#lx playpump already stopped"));
1334        return;
1335    }
1336    p->consumerStarted = false; /* don't pause on Start */
1337
1338    NEXUS_UnregisterEvent(p->playEventHandle);
1339    if (p->state.pacing) {
1340        NEXUS_Playpump_P_UninstallRangeErrIntHandler(p);
1341        rc = BXPT_Playback_ConfigPacing(p->xpt_play, BXPT_PacingControl_eStop);
1342        if (rc!=BERR_SUCCESS) {
1343            BDBG_ERR(("ignored error %#x from BXPT_Playback_ConfigPacing", rc));
1344        }
1345        p->state.pacing = false;
1346    }
1347    rc = NEXUS_Playpump_Flush(p);
1348    if (rc!=BERR_SUCCESS) {rc=BERR_TRACE(rc);}
1349
1350    /* after we've flushed, we can state we're not running */
1351    p->state.running = false;
1352    p->state.muxInput = false;
1353
1354    p->settings.playRate = NEXUS_NORMAL_PLAY_SPEED; /* reset a play rate */
1355#if B_HAS_MEDIA
1356    if (p->state.packetizer==b_play_packetizer_media) {
1357        b_pump_demux_stop(p->demux);
1358    } else
1359#endif
1360    if (p->state.packetizer==b_play_packetizer_crypto) {
1361        b_pump_crypto_stop(p->crypto);
1362    } else {
1363        BPVRlib_Feed_Stop(p->play_feed);
1364    }
1365
1366    for(play_pid=BLST_S_FIRST(&p->pid_list);play_pid!=NULL;play_pid=BLST_S_NEXT(play_pid, link)) {
1367        NEXUS_Playpump_P_StopPid(p, play_pid);
1368    }
1369    rc = BXPT_Playback_DisablePacketizers(p->xpt_play);
1370    if (rc!=BERR_SUCCESS) {rc=BERR_TRACE(rc);}
1371
1372    if (p->throttle_timer) {
1373        NEXUS_CancelTimer(p->throttle_timer);
1374        p->throttle_timer = NULL;
1375    }
1376
1377    NEXUS_Transport_P_IncPowerDown(false);
1378
1379    if(NEXUS_GetEnv("profile_playpump")) {
1380        NEXUS_Profile_Stop("NEXUS_Playpump");
1381    }
1382
1383    return;
1384}
1385
1386NEXUS_Error NEXUS_Playpump_Flush(NEXUS_PlaypumpHandle p)
1387{
1388    BERR_Code rc;
1389
1390    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1391
1392    if (!p->state.running) {
1393        /* no need to flush if not started. if it is stopped, BPVRlib_Feed_Stop/Start further down
1394        will have the unintentional effect of restarting playback. */
1395        return 0;
1396    }
1397    BDBG_MSG(("flushing playback buffers"));
1398
1399#if B_HAS_MEDIA
1400    if (p->state.packetizer==b_play_packetizer_media) {
1401        b_pump_demux_flush(p->demux);
1402    } else
1403#endif
1404    if (p->state.packetizer==b_play_packetizer_crypto) {
1405        b_pump_crypto_flush(p->crypto);
1406    }
1407    b_playpump_p_reset(p);
1408
1409    if (p->state.packetizer!=b_play_packetizer_media) {
1410        BPVRlib_Feed_Stop(p->play_feed);
1411        rc = BPVRlib_Feed_Start(p->play_feed);
1412        if (rc) return BERR_TRACE(rc);
1413    }
1414
1415    p->state.last_addr = NULL;
1416
1417    /* PI will clear pause, so restore it */
1418    if (p->paused) {
1419        rc = NEXUS_Playpump_SetPause(p, true);
1420        if (rc) return BERR_TRACE(rc);
1421    }
1422
1423    return NEXUS_SUCCESS;
1424}
1425
1426NEXUS_Error
1427NEXUS_Playpump_GetBuffer(NEXUS_PlaypumpHandle p, void **buffer, size_t *size)
1428{
1429    uint8_t *addr;
1430    unsigned freeSize, freeDesc;
1431
1432    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1433
1434    if (!p->state.running) {
1435        /* don't print error message, because this is a normal exit from thread processing */
1436        return NEXUS_UNKNOWN;
1437    }
1438
1439    freeSize = BFIFO_WRITE_PEEK(&p->fifo);
1440    if(freeSize==0) {
1441        BDBG_MSG_FLOW(("Playback buffer is full, keep waiting"));
1442        goto keep_waiting;
1443    }
1444    freeDesc = BFIFO_WRITE_LEFT(&p->activeFifo);
1445    if(freeDesc==0) {
1446        BDBG_MSG_FLOW(("no chunks available, waiting for any"));
1447        goto keep_waiting;
1448    }
1449    BDBG_ASSERT(BFIFO_WRITE_PEEK(&p->pendingFifo));
1450    BDBG_ASSERT(BFIFO_WRITE(&p->activeFifo)==BFIFO_WRITE(&p->pendingFifo));
1451    *size = freeSize;
1452    if(p->settings.mode==NEXUS_PlaypumpMode_eScatterGather) {
1453       if(freeSize>freeDesc*sizeof(NEXUS_PlaypumpDesc)) {
1454            *size = freeDesc*sizeof(NEXUS_PlaypumpDesc);
1455       }
1456    }
1457    addr = BFIFO_WRITE(&p->fifo);
1458    BDBG_ASSERT(addr);
1459
1460    p->state.last_addr = addr;
1461    *buffer = p->state.last_addr;
1462    BDBG_MSG_FLOW(("get_buffer %#lx, %d", (unsigned long)*buffer, *size));
1463    return 0;
1464
1465keep_waiting:
1466    *buffer = NULL;
1467    *size = 0;
1468    return 0;
1469
1470}
1471
1472NEXUS_Error NEXUS_Playpump_WriteComplete(NEXUS_PlaypumpHandle p, size_t skip, size_t amount_used)
1473{
1474    BERR_Code rc;
1475    unsigned amount_to_commit = skip + amount_used;
1476    unsigned amount_to_skip = skip;
1477
1478    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1479
1480    if (amount_to_commit > p->openSettings.fifoSize) {
1481        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1482    }
1483
1484    if (!p->state.running) {
1485        /* don't print error message, because this is a normal exit from thread processing */
1486        return NEXUS_UNKNOWN;
1487    }
1488
1489    if (!p->state.last_addr) {
1490        return BERR_TRACE(NEXUS_UNKNOWN);
1491    }
1492
1493    if (skip==0 && amount_used==0) {
1494        BDBG_MSG(("%#lx loop detected", (unsigned long)p)); /* player sends an empty entry if it's about to loop a stream */
1495    }
1496
1497    /* make sure it's in the physical memory so the chip can read it */
1498    BDBG_MSG_FLOW(("write_complete %#lx:%u %u %#lx", (unsigned long)p->state.last_addr, skip, amount_used, (unsigned long)BFIFO_WRITE(&p->activeFifo)));
1499
1500    rc = b_playpump_p_add_request(p, amount_to_skip, amount_to_commit - amount_to_skip, NULL);
1501    if (rc) return BERR_TRACE(rc);
1502
1503    p->state.last_addr = NULL;
1504
1505    return 0;
1506}
1507
1508NEXUS_Error NEXUS_Playpump_SubmitScatterGatherDescriptor(NEXUS_PlaypumpHandle p, const NEXUS_PlaypumpScatterGatherDescriptor *pDesc, size_t numDescriptors, size_t *pNumConsumed)
1509{
1510    BERR_Code rc;
1511    unsigned nFree;
1512    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1513    BDBG_ASSERT(pNumConsumed);
1514
1515    if (!p->state.running) {
1516        /* don't print error message, because this is a normal exit from thread processing */
1517        return NEXUS_UNKNOWN;
1518    }
1519
1520    *pNumConsumed = 0;
1521   
1522    nFree = BFIFO_WRITE_PEEK(&p->activeFifo);
1523    if (nFree==0 || numDescriptors==0) {
1524        return 0;
1525    }
1526    else if (nFree < numDescriptors) {
1527        numDescriptors = nFree;
1528    }
1529
1530    BDBG_MSG_FLOW(("submit_sg %#lx: %#lx", (unsigned long)p->state.last_addr, (unsigned long)BFIFO_WRITE(&p->activeFifo)));
1531
1532    rc = b_playpump_p_add_request(p, 0, numDescriptors*sizeof(NEXUS_PlaypumpScatterGatherDescriptor), pDesc);
1533    if (rc) return BERR_TRACE(rc);
1534
1535    *pNumConsumed = numDescriptors;
1536   
1537    return 0;
1538}
1539
1540NEXUS_Error NEXUS_Playpump_GetStatus(NEXUS_PlaypumpHandle p, NEXUS_PlaypumpStatus *pStatus)
1541{
1542    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1543    BDBG_ASSERT(pStatus);
1544
1545    BKNI_Memset(pStatus, 0, sizeof(*pStatus));
1546    pStatus->started = p->state.running;
1547    pStatus->fifoSize = p->openSettings.fifoSize;
1548    pStatus->descFifoSize = p->openSettings.numDescriptors;
1549    pStatus->bytesPlayed = p->state.bytes_played;
1550    pStatus->bufferBase = p->buf;
1551    pStatus->fifoDepth = BFIFO_READ_LEFT(&p->fifo);
1552    pStatus->descFifoDepth = BFIFO_READ_LEFT(&p->activeFifo);
1553    pStatus->index=p->index;
1554    pStatus->pacingTsRangeError = p->state.pacingTsRangeError;
1555    pStatus->syncErrors = 0;
1556    pStatus->resyncEvents = 0;
1557    pStatus->streamErrors = 0;
1558    pStatus->mediaPtsType = NEXUS_PtsType_eInterpolatedFromInvalidPTS;
1559    pStatus->mediaPts = 0;
1560
1561#if B_HAS_MEDIA
1562    if(p->state.packetizer==b_play_packetizer_media) {
1563        b_pump_demux_status(p->demux, pStatus);
1564    } else
1565#endif
1566    if(p->state.packetizer==b_play_packetizer_crypto) {
1567        b_pump_crypto_status(p->crypto);
1568    }
1569    return NEXUS_SUCCESS;
1570}
1571
1572void NEXUS_Playpump_P_ConsumerStarted(NEXUS_PlaypumpHandle p)
1573{
1574    BERR_Code rc;
1575    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1576    if(p->state.running && !p->consumerStarted) {
1577        rc = BXPT_Playback_Resume(p->xpt_play);
1578        if(rc!=BERR_SUCCESS) { rc=BERR_TRACE(rc);}
1579    }
1580    p->consumerStarted=true; /* don't pause on Start */
1581    return;
1582}
1583
1584static void
1585NEXUS_Playpump_P_SetPacketizerCfg(BXPT_Playback_PacketizeConfig *pkt_cfg, NEXUS_TransportType type, uint16_t oldpid, uint16_t newpid,
1586    const NEXUS_PlaypumpOpenPidChannelSettings *pSettings)
1587{
1588    BDBG_MSG(("mapping stream id %#x to pid %#x", (unsigned)oldpid, (unsigned)newpid));
1589
1590    pkt_cfg->Pid = newpid;
1591    pkt_cfg->ChannelNum = 0; /* fill this in below, after calling bsettop_p_transport_lock */
1592#if !BXPT_HAS_PID_CHANNEL_PES_FILTERING
1593    if(type == NEXUS_TransportType_eEs) {
1594        pkt_cfg->IsEs = true;
1595        pkt_cfg->PesStreamId = 0x00;
1596        pkt_cfg->IsDvd = false;
1597    } else if (type == NEXUS_TransportType_eVob) {
1598        pkt_cfg->IsEs = false;
1599        pkt_cfg->PesStreamId = 0;
1600        pkt_cfg->IsDvd = true;
1601    } else {
1602        pkt_cfg->IsEs = false;
1603        pkt_cfg->PesStreamId = oldpid;
1604        pkt_cfg->IsDvd = false;
1605    }
1606    pkt_cfg->MapAll = false;
1607    BSTD_UNUSED(pSettings);
1608#else
1609    if(type == NEXUS_TransportType_eEs) {
1610        pkt_cfg->PacketizerMode = BXPT_Playback_PacketizerMode_Es;
1611    } else {
1612        pkt_cfg->PacketizerMode = BXPT_Playback_PacketizerMode_Pes_Sid;
1613        pkt_cfg->FilterConfig.StreamId = oldpid;
1614    }
1615    if (pSettings->pidType == NEXUS_PidType_eAudio && type == NEXUS_TransportType_eVob) {
1616        switch (pSettings->pidTypeSettings.audio.codec) {
1617        case NEXUS_AudioCodec_eLpcmDvd:
1618        case NEXUS_AudioCodec_eLpcmHdDvd:
1619        case NEXUS_AudioCodec_eLpcmBluRay:
1620            pkt_cfg->PacketizerMode = BXPT_Playback_PacketizerMode_Pes_SidSubSid;
1621            pkt_cfg->FilterConfig.StreamIdAndSubStreamId.Id = (oldpid & 0xFF);
1622            pkt_cfg->FilterConfig.StreamIdAndSubStreamId.SubStreamId = 0xA0 | (oldpid>>8);
1623            break;
1624        case NEXUS_AudioCodec_eAc3Plus:
1625           pkt_cfg->PacketizerMode = BXPT_Playback_PacketizerMode_Pes_SidSubSid;
1626           pkt_cfg->FilterConfig.StreamIdAndSubStreamId.Id = (oldpid & 0xFF);
1627           pkt_cfg->FilterConfig.StreamIdAndSubStreamId.SubStreamId = 0xC0 | (oldpid>>8);
1628           break;
1629        case NEXUS_AudioCodec_eAc3:
1630           pkt_cfg->PacketizerMode = BXPT_Playback_PacketizerMode_Pes_SidSubSid;
1631           pkt_cfg->FilterConfig.StreamIdAndSubStreamId.Id = (oldpid & 0xFF);
1632           pkt_cfg->FilterConfig.StreamIdAndSubStreamId.SubStreamId = 0x80 | (oldpid>>8);
1633           break;
1634        case NEXUS_AudioCodec_eDts:
1635           pkt_cfg->PacketizerMode = BXPT_Playback_PacketizerMode_Pes_SidSubSid;
1636           pkt_cfg->FilterConfig.StreamIdAndSubStreamId.Id = (oldpid & 0xFF);
1637           pkt_cfg->FilterConfig.StreamIdAndSubStreamId.SubStreamId = 0x88 | (oldpid>>8);
1638           break;
1639        default:
1640            BDBG_WRN(("Unexpected VOB audio format %d", pSettings->pidTypeSettings.audio.codec));
1641            break;
1642       }
1643    }
1644#endif
1645}
1646
1647/* OpenPidChannel and activate packetization if needed */
1648static NEXUS_Error
1649NEXUS_Playpump_P_OpenPid(NEXUS_PlaypumpHandle p, NEXUS_P_PlaypumpPidChannel *play_pid, uint16_t oldpid, NEXUS_TransportType type,
1650    NEXUS_TransportType originalType, const NEXUS_PlaypumpOpenPidChannelSettings *pSettings, bool forcedPacketizerPid, uint16_t packetizerPid)
1651{
1652    uint16_t newpid = 0;
1653    BERR_Code rc;
1654    NEXUS_PidChannelHandle pidChannel=NULL;
1655    NEXUS_PidChannelStatus pid_status;
1656
1657    play_pid->packetizer.enable = false;
1658    play_pid->packetizer.active = false;
1659    switch (type) {
1660    default:
1661        pidChannel = NEXUS_PidChannel_P_Open(NULL, p, oldpid, &pSettings->pidSettings, p->settings.continuityCountEnabled);
1662        if(!pidChannel) { rc = BERR_TRACE(BERR_NOT_SUPPORTED); goto err_pid_channel_ts; }
1663        pidChannel->status.transportType = type;
1664        pidChannel->status.originalTransportType = originalType;
1665        goto opened;
1666
1667    case NEXUS_TransportType_eEs:
1668    case NEXUS_TransportType_eVob:
1669    case NEXUS_TransportType_eMpeg2Pes:
1670    case NEXUS_TransportType_eMpeg1Ps:
1671        break;
1672    }
1673    newpid = b_pid_map_alloc(&p->packetizer_map);
1674    if(newpid==0) {
1675        rc = BERR_TRACE(BERR_NOT_SUPPORTED);
1676        goto err_newpid;
1677    }
1678
1679    /* the remainder of this function handles packetization */
1680    NEXUS_Playpump_P_SetPacketizerCfg(&play_pid->packetizer.cfg, type, oldpid, forcedPacketizerPid?packetizerPid:newpid, pSettings);
1681
1682    pidChannel = NEXUS_PidChannel_P_Open(NULL, p, forcedPacketizerPid?packetizerPid:newpid, &pSettings->pidSettings, p->settings.continuityCountEnabled);
1683    if(!pidChannel) { rc = BERR_TRACE(BERR_NOT_SUPPORTED); goto err_pid_channel; }
1684
1685    pidChannel->status.transportType = NEXUS_TransportType_eTs;
1686    pidChannel->status.originalTransportType = originalType;
1687    pidChannel->status.remappedPid = oldpid;
1688
1689    rc = NEXUS_PidChannel_GetStatus(pidChannel, &pid_status);
1690    if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto err_pid_status; }
1691    play_pid->packetizer.context = newpid - NEXUS_P_PACKETIZER_BASE;
1692    play_pid->packetizer.cfg.ChannelNum = pid_status.pidChannelIndex;
1693    BDBG_ASSERT(newpid >= NEXUS_P_PACKETIZER_BASE);
1694
1695    play_pid->packetizer.enable = true;
1696
1697opened:
1698    play_pid->pid_channel = pidChannel;
1699    if (p->state.running) {
1700        rc = NEXUS_Playpump_P_StartPid(p, play_pid);
1701        if (rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto err_packetize; }
1702    }
1703
1704    return 0;
1705
1706err_packetize:
1707err_pid_status:
1708    NEXUS_PidChannel_P_Close(pidChannel);
1709err_pid_channel:
1710    if (newpid) {
1711        b_pid_map_free(&p->packetizer_map, newpid);
1712    }
1713err_newpid:
1714err_pid_channel_ts:
1715    play_pid->pid_channel = NULL;
1716    BDBG_ASSERT(rc);
1717    return rc;
1718}
1719
1720static void
1721NEXUS_Playpump_P_ClosePid(NEXUS_PlaypumpHandle p, NEXUS_P_PlaypumpPidChannel *play_pid)
1722{
1723#if B_HAS_MEDIA
1724    if(p->use_media) {
1725        if(p->state.running) {
1726            b_pump_demux_remove_pid(p->demux, play_pid);
1727        }
1728        b_pump_demux_close_pid(p->demux, play_pid);
1729    }
1730#endif
1731    if (p->state.running) {
1732        NEXUS_Playpump_P_StopPid(p, play_pid);
1733    }
1734
1735    if(play_pid->packetizer.enable) {
1736        b_pid_map_free(&p->packetizer_map, play_pid->packetizer.context+NEXUS_P_PACKETIZER_BASE);
1737    }
1738    NEXUS_PidChannel_P_Close(play_pid->pid_channel);
1739    return;
1740}
1741
1742void
1743NEXUS_Playpump_GetDefaultOpenPidChannelSettings(NEXUS_PlaypumpOpenPidChannelSettings *pSettings)
1744{
1745    BDBG_ASSERT(pSettings);
1746    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
1747    NEXUS_PidChannel_GetDefaultSettings(&pSettings->pidSettings);
1748    pSettings->pidType = NEXUS_PidType_eUnknown;
1749    pSettings->allowTimestampReordering = true;
1750    return;
1751}
1752
1753
1754
1755static NEXUS_PidChannelHandle
1756NEXUS_Playpump_P_OpenPidChannel_MuxImpl(NEXUS_PlaypumpHandle p, unsigned pid, const NEXUS_PlaypumpOpenPidChannelSettings *pSettings, bool forcedPacketizerPid, uint16_t packetizerPid)
1757{
1758    BERR_Code rc;
1759    NEXUS_P_PlaypumpPidChannel *play_pid;
1760    NEXUS_PlaypumpOpenPidChannelSettings settings;
1761    NEXUS_TransportType transportType;
1762
1763    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1764    if(!pSettings) {
1765        NEXUS_Playpump_GetDefaultOpenPidChannelSettings(&settings);
1766        pSettings = &settings;
1767    }
1768
1769    /* if pidChannelIndex is specified, this is a special case that requires the app to manage its pid channels more. */
1770    if (pSettings->pidSettings.pidChannelIndex != -1) {
1771        /* look up existing pid channels for the same pidChannelIndex */
1772        for(play_pid=BLST_S_FIRST(&p->pid_list); play_pid; play_pid=BLST_S_NEXT(play_pid, link)) {
1773            if((int)play_pid->pid_channel->status.pidChannelIndex == pSettings->pidSettings.pidChannelIndex) {
1774                if(play_pid->pid != pid) {
1775                    BDBG_ERR(("Cannot open the same pidChannelIndex (%d) with different pids (0x%x and 0x%x)", pSettings->pidSettings.pidChannelIndex, play_pid->pid, pid));
1776                    return NULL;
1777                }
1778                play_pid->ref_cnt++;
1779                goto done;
1780            }
1781        }
1782    /* else, allow the new NEXUS_PidChannelHandle to be opened, even if a NEXUS_PidChannelHandle already exists for this pid on a different pidChannelIndex.
1783       This is needed to support playpump multiplexing. */
1784    }
1785    else {
1786        for(play_pid=BLST_S_FIRST(&p->pid_list); play_pid; play_pid=BLST_S_NEXT(play_pid, link)) {
1787            if(play_pid->pid == pid) {
1788                BDBG_MSG(("NEXUS_Playpump_OpenPidChannel: %#lx detected duplicated pid %u (%#lx:%u)", (unsigned long)p, (unsigned)pid, (unsigned long)play_pid, play_pid->ref_cnt));
1789                if(BKNI_Memcmp(pSettings, &play_pid->settings, sizeof(*pSettings))!=0) {
1790                    BDBG_WRN(("NEXUS_Playpump_OpenPidChannel: %#lx detected duplicated pid %u (%#lx:%u) with non-compatible settings", (unsigned long)p, (unsigned)pid, (unsigned long)play_pid, play_pid->ref_cnt));
1791                }
1792                play_pid->ref_cnt++;
1793                goto done;
1794            }
1795        }
1796    }
1797
1798    play_pid = BKNI_Malloc(sizeof(*play_pid));
1799    if(!play_pid) { rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY); goto err_alloc;}
1800    transportType = p->settings.transportType;
1801    play_pid->pid = pid;
1802    play_pid->ref_cnt = 1;
1803    play_pid->settings = *pSettings;
1804#if B_HAS_MEDIA
1805    if(p->use_media) {
1806        transportType = NEXUS_TransportType_eMpeg2Pes;
1807        rc  = b_pump_demux_open_pid(p->demux, play_pid, pid, pSettings);
1808        if(rc!=NEXUS_SUCCESS) {
1809            goto err_media_open;
1810        }
1811        pid = play_pid->media_pid;
1812        if (p->state.running) {
1813            rc = b_pump_demux_add_pid(p->demux, play_pid);
1814            if(rc!=NEXUS_SUCCESS) {
1815                goto err_media_add;
1816            }
1817        }
1818    }
1819#endif
1820    rc = NEXUS_Playpump_P_OpenPid(p, play_pid, pid, transportType,
1821            p->settings.originalTransportType==NEXUS_TransportType_eUnknown?p->settings.transportType:p->settings.originalTransportType,
1822            pSettings, forcedPacketizerPid, packetizerPid);
1823    if (rc) { rc = BERR_TRACE(rc); goto err_pid_channel;}
1824    BLST_S_DICT_ADD(&p->pid_list, play_pid, NEXUS_P_PlaypumpPidChannel, pid_channel, link, err_duplicate);
1825
1826done:
1827    return play_pid->pid_channel;
1828
1829err_duplicate:
1830    BDBG_ERR(("NEXUS_Playpump_OpenPidChannel: %#lx detected duplicate pid %#lx", (unsigned long)p, (unsigned long)play_pid->pid_channel));
1831err_pid_channel:
1832#if B_HAS_MEDIA
1833    if(p->use_media && p->state.running) {
1834        b_pump_demux_remove_pid(p->demux, play_pid);
1835    }
1836err_media_add:
1837    if(p->use_media) {
1838        b_pump_demux_close_pid(p->demux, play_pid);
1839    }
1840err_media_open:
1841#endif
1842    BKNI_Free(play_pid);
1843err_alloc:
1844    return NULL;
1845}
1846
1847NEXUS_PidChannelHandle
1848NEXUS_Playpump_OpenPidChannel(NEXUS_PlaypumpHandle p, unsigned pid, const NEXUS_PlaypumpOpenPidChannelSettings *pSettings)
1849{
1850    return NEXUS_Playpump_P_OpenPidChannel_MuxImpl(p, pid, pSettings, false, 0);
1851}
1852
1853NEXUS_PidChannelHandle
1854NEXUS_Playpump_OpenPidChannel_priv( NEXUS_PlaypumpHandle p, uint16_t src_pid, uint16_t dst_pid, const NEXUS_PlaypumpOpenPidChannelSettings *pSettings )
1855{
1856    NEXUS_ASSERT_MODULE();
1857    return NEXUS_Playpump_P_OpenPidChannel_MuxImpl(p, src_pid, pSettings, true, dst_pid);
1858}
1859
1860NEXUS_Error
1861NEXUS_Playpump_ClosePidChannel(NEXUS_PlaypumpHandle p, NEXUS_PidChannelHandle pidChannel)
1862{
1863    NEXUS_Error rc;
1864    NEXUS_P_PlaypumpPidChannel *play_pid;
1865
1866    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1867    BLST_S_DICT_FIND(&p->pid_list, play_pid, pidChannel, pid_channel, link);
1868    if(play_pid==NULL) {
1869        BDBG_WRN(("NEXUS_Playpump_ClosePidChannel: %#lx can't find pid:%#lx", (unsigned long)p, (unsigned long)pidChannel));
1870        rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1871        goto err_not_found;
1872    }
1873    BDBG_ASSERT(play_pid->ref_cnt>0);
1874    play_pid->ref_cnt--;
1875    if(play_pid->ref_cnt==0) {
1876        BLST_S_DICT_REMOVE(&p->pid_list, play_pid, pidChannel, NEXUS_P_PlaypumpPidChannel, pid_channel, link);
1877        BDBG_ASSERT(play_pid);
1878        NEXUS_Playpump_P_ClosePid(p, play_pid);
1879        BKNI_Free(play_pid);
1880    }
1881    return NEXUS_SUCCESS;
1882
1883err_not_found:
1884    return rc;
1885}
1886
1887void
1888NEXUS_Playpump_CloseAllPidChannels(NEXUS_PlaypumpHandle p)
1889{
1890    NEXUS_P_PlaypumpPidChannel *play_pid;
1891    BDBG_OBJECT_ASSERT(p, NEXUS_Playpump);
1892    while(NULL!=(play_pid=BLST_S_FIRST(&p->pid_list))) {
1893        nexus_unregister_NEXUS_PidChannelHandle(nexus_transport_client(), play_pid->pid_channel, false);
1894        NEXUS_Playpump_ClosePidChannel(p, play_pid->pid_channel);
1895    }
1896    return;
1897}
1898
1899/* This function was added for low-level control required for IP STB flow control. */
1900NEXUS_Error NEXUS_Playpump_SetPause( NEXUS_PlaypumpHandle p, bool paused )
1901{
1902    BERR_Code rc;
1903    if (paused) {
1904        rc = BXPT_Playback_Pause(p->xpt_play);
1905        if (rc) return BERR_TRACE(rc);
1906    }
1907    else {
1908        rc = BXPT_Playback_Resume(p->xpt_play);
1909        if (rc) return BERR_TRACE(rc);
1910    }
1911    p->paused = paused;
1912    return 0;
1913}
1914
1915NEXUS_Error NEXUS_Playpump_SuspendPacing( NEXUS_PlaypumpHandle p, bool suspended )
1916{
1917    BERR_Code rc;
1918    rc = BXPT_Playback_ConfigPacing(p->xpt_play, suspended?BXPT_PacingControl_eStop:BXPT_PacingControl_eStart);
1919    if (rc) return BERR_TRACE(rc);
1920    return 0;
1921}
1922
1923static void NEXUS_Playpump_P_PacingErr_isr( void *playpump, int param2 )
1924{
1925    NEXUS_PlaypumpHandle p = (NEXUS_PlaypumpHandle)playpump;
1926    BSTD_UNUSED(param2);
1927    p->state.pacingTsRangeError++;
1928    return;
1929}
1930
1931static void NEXUS_Playpump_P_InstallRangeErrIntHandler(NEXUS_PlaypumpHandle p)
1932{
1933    BERR_Code rc;
1934    rc = BINT_CreateCallback(&p->pacingErrIntCallback, g_pCoreHandles->bint, BXPT_Playback_GetIntId(p->xpt_play, BXPT_PbInt_eTsRangeErr),
1935        NEXUS_Playpump_P_PacingErr_isr, ( void * ) p, 0 );
1936    if (!rc) {
1937        rc = BINT_EnableCallback(p->pacingErrIntCallback);
1938    }
1939    if (rc) {rc = BERR_TRACE(rc);}
1940}
1941
1942static void NEXUS_Playpump_P_UninstallRangeErrIntHandler(NEXUS_PlaypumpHandle p)
1943{
1944    (void)BINT_DestroyCallback(p->pacingErrIntCallback);
1945}
1946
1947#if NEXUS_PARSER_BAND_CC_CHECK
1948void NEXUS_Playpump_P_CCError_isr(void *context, int param)
1949{
1950    NEXUS_PlaypumpHandle p = context;
1951    BSTD_UNUSED(param);
1952    NEXUS_ParserBand_P_CountCcErrors_isr();
1953    NEXUS_IsrCallback_Fire_isr(p->ccErrorCallback);
1954}
1955#endif
1956
1957void NEXUS_Playpump_P_TeiError_isr(void *context, int param)
1958{
1959    NEXUS_PlaypumpHandle p = context;
1960    BSTD_UNUSED(param);
1961    NEXUS_IsrCallback_Fire_isr(p->teiErrorCallback);
1962}
1963
1964static NEXUS_Error NEXUS_Playpump_P_SetInterrupts(NEXUS_PlaypumpHandle p, const NEXUS_PlaypumpSettings *pSettings)
1965{
1966    BERR_Code rc;
1967
1968    /* only enable certain interrupts when their callbacks are desired. this helps typical system performance. */
1969#if NEXUS_PARSER_BAND_CC_CHECK
1970    if (pSettings->ccError.callback) {
1971        if (!p->ccErrorInt) {
1972            BDBG_MSG(("create playpump %d cc callback", p->index));
1973            rc = BINT_CreateCallback(&p->ccErrorInt, g_pCoreHandles->bint,
1974                BXPT_Playback_GetIntId(p->xpt_play, BCHP_XPT_PB0_INTR_PARSER_CONTINUITY_ERROR_SHIFT),
1975                NEXUS_Playpump_P_CCError_isr, p, 0);
1976            if (rc) return BERR_TRACE(rc);
1977            rc = BINT_EnableCallback(p->ccErrorInt);
1978            if (rc) return BERR_TRACE(rc);
1979        }
1980    }
1981    else if (p->ccErrorInt) {
1982        (void)BINT_DestroyCallback(p->ccErrorInt);
1983        p->ccErrorInt = NULL;
1984    }
1985#endif
1986
1987    /* only enable certain interrupts when their callbacks are desired. this helps typical system performance. */
1988    if (pSettings->teiError.callback) {
1989        if (!p->teiErrorInt) {
1990            BDBG_MSG(("create playpump %d tei callback", p->index));
1991            rc = BINT_CreateCallback(&p->teiErrorInt, g_pCoreHandles->bint,
1992                BXPT_Playback_GetIntId(p->xpt_play, BCHP_XPT_PB0_INTR_PARSER_TRANSPORT_ERROR_SHIFT),
1993                NEXUS_Playpump_P_TeiError_isr, p, 0);
1994            if (rc) return BERR_TRACE(rc);
1995            rc = BINT_EnableCallback(p->teiErrorInt);
1996            if (rc) return BERR_TRACE(rc);
1997        }
1998    }
1999    else if (p->teiErrorInt) {
2000        (void)BINT_DestroyCallback(p->teiErrorInt);
2001        p->teiErrorInt = NULL;
2002    }
2003
2004    NEXUS_IsrCallback_Set(p->ccErrorCallback, &pSettings->ccError);
2005    NEXUS_IsrCallback_Set(p->teiErrorCallback, &pSettings->teiError);
2006
2007    return 0;
2008}
2009
2010NEXUS_Error NEXUS_Playpump_GetAllPassPidChannelIndex(
2011    NEXUS_PlaypumpHandle playpump, 
2012    unsigned *pHwPidChannel
2013    )
2014{
2015    BDBG_OBJECT_ASSERT(playpump, NEXUS_Playpump);
2016    BDBG_ASSERT(pHwPidChannel);
2017
2018    *pHwPidChannel = BXPT_GET_PLAYBACK_ALLPASS_CHNL( playpump->index );
2019    return 0;
2020}
2021
Note: See TracBrowser for help on using the repository browser.