source: svn/newcon3bcm2_21bu/nexus/lib/playback_ip/apps/ip_client.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: 125.5 KB
Line 
1/******************************************************************************
2 *    (c)2008-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: ip_client.c $
39 * $brcm_Revision: 64 $
40 * $brcm_Date: 11/30/11 4:40p $
41 *
42 * Module Description:
43 *  Example program to demonstrate receiving live or playback content over IP Channels (UDP/RTP/RTSP/HTTP based)
44 *
45 * Revision History:
46 *
47 * $brcm_Log: /nexus/lib/playback_ip/apps/ip_client.c $
48 *
49 * 64   11/30/11 4:40p mward
50 * SW7429-1:  Allow build with NEXUS_NUM_AUDIO_DACS 0 and/or
51 *  NEXUS_NUM_SPDIF_OUTPUTS 0
52 *
53 * 63   10/21/11 2:03p ssood
54 * SW7231-405: fix scaler before capture for HLS sessions inorder to avoid
55 *  black frames during bitrate/resolution transitions
56 *
57 * 62   9/1/11 2:38p hongtaoz
58 * SW7425-504: fixed quit errors;
59 *
60 * 61   8/29/11 7:04p hongtaoz
61 * SW7425-504: configure sync channel properly if audio is not present to
62 *  avoid 3 seconds mute at decode;
63 *
64 * 60   8/29/11 2:28p hongtaoz
65 * SW7425-504: fixed PCR channel failure with video only test;
66 *
67 * 59   8/25/11 8:11a jrubio
68 * SW7125-1088: fix coverity issue
69 *
70 * 58   8/25/11 8:01a jrubio
71 * SW7125-1088: fix coverity issue
72 *
73 * 57   8/23/11 4:42p jrubio
74 * SW7344-181: coverity fix CID 35300
75 *
76 * 56   8/23/11 4:35p jrubio
77 * SW7344-181: coverity fix
78 *
79 * 55   8/17/11 10:36a ssood
80 * SW7425-1040: coverity fix
81 *
82 * 54   8/7/11 7:00p ssood
83 * SW7425-1040: more changes to support FCC over IP sessions
84 *
85 * 53   8/4/11 4:45p ssood
86 * SW7425-1040: add fast channel change support to IP Sessions
87 *
88 * 52   7/14/11 11:09a ssood
89 * SW7420-1978: get ip_client to work in the slave mode
90 *
91 * 51   7/11/11 12:09p ssood
92 * SW7231-268: add nexus sync channel support in ip_client for better AV
93 *  lipsync
94 *
95 * 50   6/21/11 9:43p qsong
96 * SWDTV-7634: Make it build against latest 233 nexus.
97 *
98 * 49   6/6/11 1:28a ssood
99 * SW7231-166: added support for Slow Fwd, STC Based trick play at 2X, and
100 *  eventCallback support for end of stream playback
101 *
102 * 48   6/3/11 5:31p ssood
103 * SW7231-166: fixed api call sequence for the case where a format doesn't
104 *  have any index info
105 *
106 * 47   5/31/11 10:12a ssood
107 * SW7231-166: require apps to set contentLengthHint for allowing
108 *  trickmodes on streaming content from DLNA Servers using HTTP Chunk
109 *  Xfer Encoding
110 *
111 * 46   5/26/11 11:31p ssood
112 * SW7231-166: dont create Nexus File Handle for cases where Nexus
113 *  playpump will get used
114 *
115 * 45   5/25/11 3:35p ssood
116 * SW7231-166: fixed some bugs during failing trickplay cases
117 *
118 * 44   5/24/11 11:35a ssood
119 * SW7405-4392: Coverity fixes
120 *
121 * 43   5/23/11 3:44p ssood
122 * SW7231-166: Extend Playback IP trickmodes to be compatible with latest
123 *  DLNA Guidelines
124 *
125 * 42   5/19/11 4:28p ssood
126 * SW7420-1774: Add support to decode SVC/MVC videos
127 *
128 * 41   3/28/11 11:03a ssood
129 * SW7420-502: reset the wait event
130 *
131 * 40   3/21/11 5:39p ssood
132 * SW7420-502: rvu support: enable timestamp mode if server sends 192byte
133 *  TS packets
134 *
135 * 39   3/8/11 4:00p ssood
136 * SWDTV-5698: increase the timeout for session callback event
137 *
138 * 38   2/24/11 1:42p ssood
139 * SW7420-502: clock recovery support for RVU client
140 *
141 * 37   2/13/11 4:38p root
142 * SW7422-161:Add extra parameter to fix DTCP build error
143 *
144 * 36   1/7/11 3:30p jtna
145 * SW7422-165: use NEXUS_VideoDecoderStatus.ptsStcDifference to calculate
146 *  PTS - STC difference
147 *
148 * 35   12/15/10 10:47a mward
149 * SW7420-1217: Include nexus_dma.h to fix warning.
150 *
151 * 34   12/14/10 2:09p ssood
152 * SW7420-1217: support case where app doesn't a-priori know that it needs
153 *  to play a HLS URI
154 *
155 * 33   12/14/10 12:08p ssood
156 * SW7420-1217: add support for encryption key parsing, downloading and
157 *  receiving encrypted content
158 *
159 * 32   12/7/10 12:10a ssood
160 * SW7420-1257: fixed warning
161 *
162 * 31   12/7/10 12:00a ssood
163 * SW7420-1257: support for playing H264 encoded video conference stream
164 *
165 * 30   11/24/10 2:58p ssood
166 * SW7420-1257: Video Conferencing Demo: add support for receiving input
167 *  camera input and stream it out
168 *
169 * 29   11/15/10 5:10p ssood
170 * SW7420-1217: limited file playback duration check to HLS protocol only
171 *
172 * 28   10/29/10 9:07a ssood
173 * SW7420-1217: basic support to play both variant & non-variant bounded
174 *  playlists containing clear content
175 *
176 * 27   10/8/10 6:24p ssood
177 * SW7420-1088: extended ip_client to auto test trickmode cases
178 *
179 * 26   10/8/10 10:41a mward
180 * SWGERRARD-547: unused variable 'playbackIpStatus'.
181 *
182 * 25   10/6/10 6:25p ssood
183 * SWGERRARD-547: added flag for LPCM playback & auto testing
184 *
185 * 24   9/24/10 5:49p ssood
186 * SWGERRARD-547: added support for seeks on ES files (MP3, WMA w/o index)
187 *
188 * 23   9/17/10 8:21a ssood
189 * SWGERRARD-547: support to expose multiple multiple programs and tracks
190 *  within a multi-program stream
191 *
192 * 22   8/27/10 3:59p ssood
193 * SW7420-502: added partial support to play RVU sessions in live mode
194 *
195 * 21   4/16/10 5:02p ssood
196 * SW7420-561: Added support for Additional Philips RTSP features:
197 *  configurable keepalive timer, allow apps to send custom headers to
198 *  servers, generate EOF events to app upon RTSP heartbeat failures
199 *
200 * 20   4/2/10 5:57p ssood
201 * SW7420-561: add support to handle large URLs (HTML5 URLs can be over
202 *  256bytes) + Coverity fixes
203 *
204 * 19   3/15/10 4:40p ssood
205 * SW7125-233: Coverity fixes
206 *
207 * 18   3/10/10 12:39p ssood
208 * SW7420-561: removed nexus dependency for simple file streaming (no
209 *  DTCP/IP or Live streaming support)
210 *
211 * 17   3/4/10 12:17p ssood
212 * SW7420-561: merge from branch to mainline
213 *
214 * SW7420-561/3   3/4/10 11:53a ssood
215 * SW7420-561: added comments
216 *
217 * SW7420-561/2   2/16/10 10:42p ssood
218 * SW7420-561: Changes to support basic RTSP w/o trickmodes
219 *
220 * SW7420-561/1   2/16/10 10:13a ssood
221 * SW7420-561: initial cut of new APIs to meet Media Browser, DMR, &
222 *  Philips RTSP requirements
223 *
224 * 15   1/23/10 10:17a ssood
225 * SW7420-454: further changes to condense the ip playback log
226 *
227 * 14   1/20/10 5:30p ssood
228 * SW7420-454: added option to compile out auto PSI detection via
229 *  AUTO_PSI_SUPPORT=n
230 *
231 * 13   12/22/09 11:11a ssood
232 * SW7420-454: switch pause method to connection stalling to demonstrate
233 *  pause on live channels
234 *
235 * 12   12/16/09 3:28p ssood
236 * SW7420-454: extend ip_client app to support fast rewind
237 *
238 * 11   11/19/09 9:23p ssood
239 * SW7420-454: no need to set playback override flag to av decoders, stc
240 *  channel ePcr mode is enough to indicate live IP playback
241 *
242 * 10   11/17/09 12:44p ssood
243 * SW7420-454: fixed compilation warning
244 *
245 * 9   11/17/09 12:41p ssood
246 * SW7420-454: add an option for dtcp ake port
247 *
248 * 8   10/28/09 9:48a ssood
249 * SW7405-2681: add nexus error callback
250 *
251 * 7   10/6/09 12:18p ssood
252 * SW7420-340: Add DTCP/IP support to ip_streamer & IP Applib
253 *
254 * 6   9/25/09 3:43p ismailk
255 * SW7405-3080: Include "b_dtcp_applib.h" under #ifdef B_HAS_DTCP_IP
256 *
257 * 5   9/21/09 12:09p ssood
258 * SW7405-2559: Adding LPCM playback support
259 *
260 * 4   9/16/09 4:20p ssood
261 * SW7420-340: print debug stats
262 *
263 *
264 *
265 ******************************************************************************/
266#include "ip_includes.h"
267#ifdef B_HAS_DTCP_IP
268#include "b_dtcp_applib.h"
269#endif
270#include "b_os_lib.h"
271
272#ifdef B_AUTO_PSI_SUPPORT
273#include "b_psip_lib.h"
274#include "ip_psi.h"
275#endif
276#include "nexus_core_utils.h"
277#include "nexus_video_decoder_primer.h"
278#include "nexus_video_decoder_extra.h"
279#include "bmedia_probe.h"
280#include "nexus_dma.h"
281#if NEXUS_DTV_PLATFORM
282#include "nexus_platform_boardcfg.h"
283#endif
284#if NEXUS_HAS_SYNC_CHANNEL
285#include "nexus_sync_channel.h"
286#endif
287
288BDBG_MODULE(ip_client);
289#define CA_CERT "./host.cert"
290
291/* Test App to demonstrate the Live IP tuning using Nexus IP Applib */
292#define IP_NETWORK_JITTER 300
293#define TOTAL_PRIMERS 1
294
295/*TODO - For now use these three Nexus as globals.  Should ideally be placed */
296/*       within context varible of HDMI callback                           */
297NEXUS_AudioDecoderStartSettings audioProgram;
298NEXUS_AudioDecoderHandle pcmDecoder = NULL, compressedDecoder = NULL;
299
300bool audioStarted = false;
301
302typedef struct {
303    int iphVersion;
304    char host[256];     /* IP Address of Receiving Host */
305    char *port;     /* Port # */
306    char *url;      /* URL */
307    B_PlaybackIpProtocol protocol; /* Protocol: UDP/RTP */
308    bool useLiveIpMode;
309    bool decoderStats;
310    B_PlaybackIpSecurityProtocol security;  /* which security protocol to use */
311    unsigned int preChargeTime;  /* how many seconds to precharge the buffers before display begings */
312    int initialSeekTime; /* how many seconds to seek into the media before starting the initial playback */
313    bool loop; /* loop around at end */
314    bool playMp3; /* play MP3 */
315    bool playLpcm; /* play LPCM */
316    int secondsToJump;
317    int dtcpAkePort;
318    bool serverBasedTrickModes; /* set if user wants us to use the server side trickmodes */
319    bool slaveMode;
320    bool runUnitTests;
321    bool playMultipleStreams;
322    bool skipPsiParsing;
323    bool fastChannelChange;
324}ExampleIpCfg;
325
326int feedToPlayback = 0;
327
328void usage(void)
329{
330    printf("Usage: ip_client -d <ip> -p <port> [-t <num>] [-u <url>] [-v <num>] [-S <num>] [-b <num>] [-i <num>] [-l <num>] -j <num> [-c] [-y] [-k] [-f] [-h] \n");
331    printf("options are:\n");
332    printf(" -d <ip>        # IP address of Live IP Channel (e.g. 192.168.1.110)\n");
333    printf(" -p <port>      # Port of Live IP Channel (e.g. 1234)\n");
334    printf(" -t <0|1|2|3|4> # protocol: UDP(0)|RTP(1)|RTSP(2)|HTTP(3)|RTP w/o RTCP(4), default is UDP\n");
335    printf(" -u <url>       # URL for RTSP & HTTP protocols\n");
336    printf(" -v             # IP version to use: IPv4: 4, IPv6: 6, default is IPv4\n");
337    printf(" -s             # print decoder stats\n");
338    printf(" -S <0|1|2|3|4> # Security: none(0) | SSL(1) | DTCP-IP(2) | RAD-EA(3) | AES128(4), default is none\n");
339    printf(" -b <time>      # pre-charge the buffers for <time> seconds, default is 0\n");
340    printf(" -i <time>      # initial seek time in seconds, default is 0\n");
341    printf(" -j <num>       # jump forward/backward by these many seconds when j is pressed\n");
342    printf(" -l <num>       # loop around after end, default is true\n");
343    printf(" -n <ake-port>  # DTCP/IP AKE Port, default 8000\n");
344    printf(" -m             # play MP3 (skips media probing)\n");
345    printf(" -r             # use server based trickmodes (default client based)\n");
346    printf(" -z             # run in slave mode\n");
347    printf(" -y             # run basic unit tests on the stream (seek, pause, ff, fr, etc.)\n");
348    printf(" -c             # play lpcm file\n");
349    printf(" -k             # skip psi parsing (PSI info is harded in ip_client.c) \n");
350    printf(" -f             # use fast channel \n");
351    printf(" -h             # prints this usage\n");
352    printf("\n");
353}
354
355static void set_default_ip_cfg(ExampleIpCfg *ipCfg)
356{
357    memset(ipCfg, 0, sizeof(ExampleIpCfg));
358
359    ipCfg->protocol = B_PlaybackIpProtocol_eUdp;
360    ipCfg->iphVersion = 4;
361    ipCfg->port = NULL;
362    ipCfg->url = NULL;
363    ipCfg->decoderStats = false;
364    ipCfg->preChargeTime = 0;
365    ipCfg->security = B_PlaybackIpSecurityProtocol_None;
366    ipCfg->initialSeekTime = 0;
367    ipCfg->loop = true;
368    ipCfg->playMp3 = false;
369    ipCfg->dtcpAkePort = 8000;
370    ipCfg->playLpcm = false;
371    ipCfg->secondsToJump = 5;
372    ipCfg->serverBasedTrickModes = false;
373    ipCfg->slaveMode = false;
374    ipCfg->runUnitTests = false;
375    ipCfg->playMultipleStreams = false;
376    ipCfg->fastChannelChange = false;
377}
378
379static int parse_options(int argc, char *argv[], ExampleIpCfg *ipCfg)
380{
381    int ch;
382    while ( (ch = getopt(argc, argv, "d:p:v:t:u:sS:b:i:l:j:n:zmrcxykfh")) != -1) {
383        switch (ch) {
384        case 'd':
385            strncpy(ipCfg->host, optarg, sizeof(ipCfg->host)-1);
386            break;
387        case 'p':
388            ipCfg->port = optarg;
389            break;
390        case 'n':
391            ipCfg->dtcpAkePort = atoi(optarg);
392            break;
393        case 't':
394            ipCfg->protocol = (B_PlaybackIpProtocol)atoi(optarg);
395            if (ipCfg->protocol >= B_PlaybackIpProtocol_eMax) {
396                BDBG_ERR(("Incorrect Protocol Option (%d)\n", ipCfg->protocol));
397                goto usage;
398            }
399            break;
400        case 'u':
401            ipCfg->url = optarg;
402            BDBG_ERR(("URL is %s\n", ipCfg->url));
403            break;
404        case 'v':
405            ipCfg->iphVersion = atoi(optarg);
406            if (ipCfg->iphVersion != 4 && ipCfg->iphVersion != 6) {
407                BDBG_ERR(("Incorrect IP Version (%d)\n", ipCfg->iphVersion));
408                goto usage;
409            }
410            break;
411        case 'f':
412            ipCfg->fastChannelChange = true;
413            break;
414        case 's':
415            ipCfg->decoderStats = true;
416            break;
417        case 'S':
418            ipCfg->security = (B_PlaybackIpSecurityProtocol)atoi(optarg);
419            if (ipCfg->security > B_PlaybackIpSecurityProtocol_Max) {
420                BDBG_ERR(("Incorrect Security Option (%d)\n", ipCfg->security));
421                goto usage;
422            }
423            break;
424        case 'b':
425            ipCfg->preChargeTime = atoi(optarg);
426            break;
427        case 'i':
428            ipCfg->initialSeekTime = atoi(optarg);
429            if (ipCfg->initialSeekTime < 0) {
430                BDBG_ERR(("Incorrect initial seek time (%d)\n", ipCfg->initialSeekTime));
431                goto usage;
432            }
433            break;
434        case 'j':
435            ipCfg->secondsToJump = atoi(optarg);
436            break;
437        case 'l':
438            ipCfg->loop = atoi(optarg);
439            break;
440        case 'm':
441            ipCfg->playMp3 = true;
442            break;
443        case 'r':
444            ipCfg->serverBasedTrickModes = true;
445            break;
446        case 'z':
447            ipCfg->slaveMode = true;
448            break;
449        case 'c':
450            ipCfg->playLpcm = true;
451            break;
452        case 'y':
453            ipCfg->runUnitTests = true;
454            break;
455        case 'x':
456            ipCfg->playMultipleStreams = true;
457            break;
458        case 'k':
459            ipCfg->skipPsiParsing = true;
460            break;
461        case 'h':
462        default:
463usage:
464            usage();
465            exit(1);
466        }
467    }
468    if (ipCfg->port == NULL) {
469        BDBG_ERR(("ERROR: Missing %s option\n", "-p"));
470        usage();
471        return -1;
472    }
473
474    if ((ipCfg->protocol == B_PlaybackIpProtocol_eRtsp || ipCfg->protocol == B_PlaybackIpProtocol_eHttp) && (ipCfg->url == NULL)) {
475        BDBG_ERR(("ERROR: RTSP & HTTP protocols require URL option\n"));
476        usage();
477        return -1;
478    }
479    BDBG_WRN(("Options are: \n\tHost: %s\n\tPort %s\n\tProtocol %s\n\tUrl %s\n\tIpVersion %d\n",
480            ipCfg->host, ipCfg->port, 
481            ipCfg->protocol == B_PlaybackIpProtocol_eUdp ? "UDP" : 
482            ipCfg->protocol == B_PlaybackIpProtocol_eRtp ? "RTP" : 
483            ipCfg->protocol == B_PlaybackIpProtocol_eRtpNoRtcp ? "RTP no RTCP" : 
484            ipCfg->protocol == B_PlaybackIpProtocol_eRtsp ? "RTSP" : "HTTP",
485            ipCfg->url,
486            ipCfg->iphVersion));
487    return 0;
488}
489
490ExampleIpCfg ipCfg;
491int ip_client_setup(int argc, char *argv[])
492{
493
494    /* set the IP socket related defults for program */
495    set_default_ip_cfg(&ipCfg);
496
497    /* parse command line options */
498    if (parse_options(argc, argv, &ipCfg)) {
499        BDBG_WRN(("ERROR: Incorrect Options\n"));
500        goto error;
501    }
502
503    return 0;
504
505error:
506    return 1;
507}
508
509void setDefaultPsiSettings(B_PlaybackIpPsiInfo *psi)
510{
511    memset(psi, 0, sizeof(*psi));
512    psi->psiValid = true;
513    psi->videoCodec = NEXUS_VideoCodec_eMpeg2;
514    psi->videoPid = 0x11;
515    psi->audioCodec = NEXUS_AudioCodec_eAc3;
516    psi->audioPid = 0x14;
517    psi->pcrPid = 0x11;
518    psi->mpegType = NEXUS_TransportType_eTs;
519    BDBG_WRN(("Setting Default PSI Settings: vpid %d, vcodec %d, apid %d, acodec %d, container %d", psi->videoPid, psi->videoCodec, psi->audioPid, psi->audioCodec, psi->mpegType));
520}
521
522
523#if NEXUS_NUM_HDMI_OUTPUTS
524static void disconnect_hdmi_audio(NEXUS_HdmiOutputHandle hdmi)
525{
526    NEXUS_AudioDecoderHandle decoder;
527
528    if ( audioProgram.codec == NEXUS_AudioCodec_eAc3 )
529    {
530        decoder = compressedDecoder;
531    }
532    else
533    {
534        decoder = pcmDecoder;
535    }
536
537    if ( audioStarted )
538        NEXUS_AudioDecoder_Stop(decoder);
539
540    NEXUS_AudioOutput_RemoveAllInputs(NEXUS_HdmiOutput_GetAudioConnector(hdmi));
541
542    if ( audioStarted )
543        NEXUS_AudioDecoder_Start(decoder, &audioProgram);
544}
545
546static void connect_hdmi_audio(NEXUS_HdmiOutputHandle hdmi)
547{
548    NEXUS_AudioDecoderHandle decoder;
549    NEXUS_AudioInput connector;
550
551    if ( audioProgram.codec == NEXUS_AudioCodec_eAc3 )
552    {
553        decoder = compressedDecoder;
554        connector = NEXUS_AudioDecoder_GetConnector(decoder, NEXUS_AudioDecoderConnectorType_eCompressed);
555    }
556    else
557    {
558        decoder = pcmDecoder;
559        connector = NEXUS_AudioDecoder_GetConnector(decoder, NEXUS_AudioDecoderConnectorType_eStereo);
560    }
561
562    if ( audioStarted )
563        NEXUS_AudioDecoder_Stop(decoder);
564
565    NEXUS_AudioOutput_AddInput(NEXUS_HdmiOutput_GetAudioConnector(hdmi), connector);
566
567    if ( audioStarted )
568        NEXUS_AudioDecoder_Start(decoder, &audioProgram);
569}
570static void hotplug_callback(void *pParam, int iParam)
571{
572    NEXUS_Error rc;
573    static bool connected = false;
574    NEXUS_HdmiOutputStatus status;
575    NEXUS_HdmiOutputHandle hdmi = pParam;
576    NEXUS_DisplayHandle display = (NEXUS_DisplayHandle)iParam;
577    NEXUS_DisplaySettings displaySettings;
578
579    NEXUS_HdmiOutput_GetStatus(hdmi, &status);
580
581    if ( connected != status.connected )
582    {
583        if ( connected )
584        {
585            fprintf(stderr, "\nHotplug - Disconnecting HDMI from display\n");
586            disconnect_hdmi_audio(hdmi);
587            rc = NEXUS_Display_RemoveOutput(display, NEXUS_HdmiOutput_GetVideoConnector(hdmi));           
588            if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); exit(-1);}
589        }
590        else
591        {
592            NEXUS_Display_GetSettings(display, &displaySettings);
593            if ( !status.videoFormatSupported[displaySettings.format] )
594            {
595                fprintf(stderr, "\nCurrent format not supported by attached monitor.  Switching to preferred format %d", status.preferredVideoFormat);
596                displaySettings.format = status.preferredVideoFormat;
597                NEXUS_Display_SetSettings(display, &displaySettings);
598            }
599
600            fprintf(stderr, "\nHotplug - connecting HDMI to display\n");
601            rc = NEXUS_Display_AddOutput(display, NEXUS_HdmiOutput_GetVideoConnector(hdmi));
602            if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); exit(-1);}
603            connect_hdmi_audio(hdmi);
604        }
605        connected = status.connected;
606    }
607}
608#endif
609
610bool gEof = false;
611static void errorCallback(void *context, int param)
612{
613    BSTD_UNUSED(param);
614    BSTD_UNUSED(context);
615    gEof = true;
616    BDBG_ERR((" #### Error callback, setting EOF flag to terminate playback session #### \n"));
617}
618
619static void endOfStreamCallback(void *context, int param)
620{
621    BSTD_UNUSED(param);
622    BSTD_UNUSED(context);
623    gEof = true;
624    BDBG_ERR((" #### End of stream reached #### \n"));
625}
626
627/* returns 0 for successful buffering or -1 otherwise */
628int preChargeNetworkBuffer(B_PlaybackIpHandle playbackIp, unsigned int preChargeTime /* in secs */)
629{
630    NEXUS_Error rc;
631    B_PlaybackIpSettings playbackIpSettings;
632    B_PlaybackIpStatus playbackIpStatus;
633    NEXUS_PlaybackPosition prevBufferDuration = 0;
634    int noChangeInBufferDepth = 0;
635
636    /* check for EOF condition */
637    if (gEof) {
638        BDBG_WRN(("Buffering Aborted due to EOF\n"));
639        return -1;
640    }
641
642    /* check how much data is currently buffered: this is from the last seek point */
643    BKNI_Sleep(100);    /* sleep little bit to get IP thread finish off any buffering */
644    rc = B_PlaybackIp_GetStatus(playbackIp, &playbackIpStatus);
645    if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); return (-1);}
646    if (playbackIpStatus.curBufferDuration >= (1000*preChargeTime)) {
647        BDBG_WRN(("Already buffered %lu milli-sec of data, required %u milli-sec of buffer...\n", playbackIpStatus.curBufferDuration, preChargeTime*1000));
648        return 0;
649    }
650
651    /* underflowing in network buffer, tell IP Applib to start buffering */
652    BDBG_WRN(("Start pre-charging n/w buffer: currently buffered %lu milli-sec of data, required %u milli-sec of buffer...\n", playbackIpStatus.curBufferDuration, preChargeTime*1000));
653    memset(&playbackIpSettings, 0, sizeof(playbackIpSettings));
654    playbackIpSettings.preChargeBuffer = true;
655    rc = B_PlaybackIp_SetSettings(playbackIp, &playbackIpSettings);
656    if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); return (-1);}
657
658    /* now monitor the buffer depth until it reaches the desired preChargeTime value */
659    do {
660        BKNI_Sleep(100);
661        rc = B_PlaybackIp_GetStatus(playbackIp, &playbackIpStatus);
662        if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); return (-1);}
663        BDBG_WRN(("currently buffered %lu milli-sec of data, max duration %d, required %u milli-sec of buffer...\n", playbackIpStatus.curBufferDuration, playbackIpStatus.maxBufferDuration, preChargeTime*1000));
664        if (playbackIpStatus.curBufferDuration >= playbackIpStatus.maxBufferDuration) {
665            BDBG_WRN(("currently buffered %lu max duration %d milli-sec worth data, so done buffering \n", playbackIpStatus.curBufferDuration, playbackIpStatus.maxBufferDuration));
666            break;
667        }
668        if (!prevBufferDuration)
669            prevBufferDuration = playbackIpStatus.curBufferDuration;
670        else {
671            if (prevBufferDuration == playbackIpStatus.curBufferDuration)
672                noChangeInBufferDepth++;
673            else  {
674                noChangeInBufferDepth = 0;
675                prevBufferDuration = playbackIpStatus.curBufferDuration;
676            }
677        }
678        if (noChangeInBufferDepth >= 10) {
679            BDBG_WRN(("Warning: can't buffer upto the required buffer depth, currently buffered %lu max duration %d milli-sec worth data, so done buffering \n", playbackIpStatus.curBufferDuration, playbackIpStatus.maxBufferDuration));
680            break;
681        }
682        /* keep buffering until we have buffered upto the high water mark or eof/server close events happen */
683    } while (playbackIpStatus.curBufferDuration < (1000*preChargeTime) && !gEof && !playbackIpStatus.serverClosed); 
684
685    /* tell IP Applib to stop buffering */
686    playbackIpSettings.preChargeBuffer = false;
687    rc = B_PlaybackIp_SetSettings(playbackIp, &playbackIpSettings);
688    if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); return (-1);}
689
690    if (gEof) {
691        BDBG_WRN(("Buffering Aborted due to EOF, buffered %lu milli-sec worth of data...\n", playbackIpStatus.curBufferDuration));
692        return -1;
693    }
694    else if (playbackIpStatus.serverClosed) {
695        BDBG_WRN(("Can't Buffer anymore due to server closed connection, buffered %lu milli-sec worth of data...\n", playbackIpStatus.curBufferDuration));
696        /* Note: this is not an error case as server may have closed connection, but we may not have played all this data, so let playback finish */
697        return 0;
698    }
699    else {
700        BDBG_WRN(("Buffering Complete (buffered %lu milli-sec worth of data), serverClosed %d...\n", playbackIpStatus.curBufferDuration, playbackIpStatus.serverClosed));
701        return 0;
702    }
703}
704
705#define EVENT_WAIT_TIME_IN_MSEC 30000
706B_PlaybackIpEventIds gEventId = B_PlaybackIpEvent_eMax;
707BKNI_EventHandle waitEvent = NULL;
708void playbackIpEventCallback(void *appCtx, B_PlaybackIpEventIds eventId)
709{
710#if 0
711    /* App can choose to either directly call the Ip API here or send an event to the app thread */
712    /* which can actually make the Ip API call. It can use the eventId to determine which call to make */
713    NEXUS_Error rc;
714    rc = B_PlaybackIp_SessionSetup(playbackIp, &ipSessionSetupSettings, &ipSessionSetupStatus);
715#endif
716    gEventId = eventId;
717    if (eventId == B_PlaybackIpEvent_eServerEndofStreamReached)
718        gEof = 1;
719    else {
720        BKNI_SetEvent(waitEvent);
721    }
722    BDBG_WRN(("%s: Got EventId %d from IP library, appCtx %p", __FUNCTION__, eventId, appCtx));
723}
724
725void 
726runPlaybackIpUnitTests(B_PlaybackIpPsiInfo *psi, B_PlaybackIpHandle playbackIp)
727{
728    B_PlaybackIpTrickModesSettings ipTrickModeSettings;
729
730        /* ip_client is also used for auto testing media streaming over IP */
731       
732        /* run tests after a stream is played for sometime */
733        sleep(5);
734
735    /* Pause */
736    B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings);
737    ipTrickModeSettings.pauseMethod = B_PlaybackIpPauseMethod_UseConnectionStalling;
738    if (B_PlaybackIp_Pause(playbackIp, &ipTrickModeSettings)) {BDBG_ERR(("ERROR: Failed to pause Ip playback\n")); goto out;}
739    BDBG_WRN(("*********** Paused Ip playback*********** \n"));
740        sleep(10);
741
742    /* Play */
743    if (B_PlaybackIp_Play(playbackIp)) {BDBG_ERR(("ERROR: Failed to pause-resume Ip playback\n")); goto out;}
744    BDBG_WRN(("*********** Pause-Resumed Ip playback*********** \n"));
745        sleep(10);
746
747        /* seek 30sec fwd */
748    B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings);
749    ipTrickModeSettings.seekPosition = 30*1000; /* in msec */
750    if (B_PlaybackIp_Seek(playbackIp, &ipTrickModeSettings)) {BDBG_ERR(("ERROR: Failed to seek Ip playback\n")); goto out;}
751    BDBG_WRN(("*********** %s: seeked successfully*********** ", __FUNCTION__));
752    sleep(10);
753
754        /* seek 120sec fwd */
755    B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings);
756    ipTrickModeSettings.seekPosition = 120*1000; /* in msec */
757    if (B_PlaybackIp_Seek(playbackIp, &ipTrickModeSettings)) {BDBG_ERR(("ERROR: Failed to seek Ip playback\n")); goto out;}
758    BDBG_WRN(("*********** %s: seeked successfully*********** ", __FUNCTION__));
759    sleep(10);
760
761        /* case:seek relative 30sec backward */
762    B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings);
763    ipTrickModeSettings.seekPositionIsRelative = true;
764    ipTrickModeSettings.seekBackward = false;
765    ipTrickModeSettings.seekPosition = 30*1000; /* in msec */
766    if (B_PlaybackIp_Seek(playbackIp, &ipTrickModeSettings)) {BDBG_ERR(("ERROR: Failed to seek Ip playback\n")); goto out;}
767    BDBG_WRN(("*********** %s: seeked successfully*********** ", __FUNCTION__));
768        sleep(10);
769
770       
771        /* skip trickplay tests for audio files */
772    if (psi->videoPid == 0)
773        return;
774
775        /* trickplay ff */
776    B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings);
777    if (ipCfg.serverBasedTrickModes) {
778        if (psi->numPlaySpeedEntries <= 1) {
779            BDBG_WRN(("Server side trickmodes not supported for this media stream: %s", ipCfg.url, psi->mpegType));
780            return;
781        }
782        ipTrickModeSettings.method = B_PlaybackIpTrickModesMethod_UsePlaySpeed;
783        ipTrickModeSettings.rate = psi->playSpeed[8];
784        if (ipTrickModeSettings.rate >= psi->httpMinIFrameSpeed)
785            ipTrickModeSettings.frameRepeat = psi->httpFrameRepeat;
786        else
787            ipTrickModeSettings.frameRepeat = 1;
788        if (B_PlaybackIp_TrickMode(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {BDBG_WRN(("Failed to set the trick play speed")); goto out;}
789        BDBG_WRN(("****************** FF Started ***************************"));
790            sleep(10);
791        if (B_PlaybackIp_Play(playbackIp)) {BDBG_ERR(("ERROR: Failed to resume from trickplay \n")); goto out;}
792            sleep(10);
793
794        /* rewind test */
795        ipTrickModeSettings.rate = psi->playSpeed[2];
796        if (B_PlaybackIp_TrickMode(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {BDBG_WRN(("Failed to set the trick play speed")); goto out;}
797        BDBG_WRN(("****************** FR Started ***************************"));
798            sleep(10);
799        if (B_PlaybackIp_Play(playbackIp)) {BDBG_ERR(("ERROR: Failed to resume from trickplay \n")); goto out;}
800
801    }
802    else {
803        ipTrickModeSettings.method = B_PlaybackIpTrickModesMethod_UseByteRange;
804        ipTrickModeSettings.rate = 5;
805        if (B_PlaybackIp_TrickMode(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {BDBG_WRN(("Failed to do client side trickmodes ")); goto out;}
806        BDBG_WRN(("****************** FF Started ***************************"));
807            sleep(10);
808        if (B_PlaybackIp_Play(playbackIp)) {BDBG_ERR(("ERROR: Failed to resume from trickplay \n")); goto out;}
809
810        /* fast rewind */
811        ipTrickModeSettings.method = B_PlaybackIpTrickModesMethod_UseByteRange;
812        ipTrickModeSettings.rate = -5;
813        if (B_PlaybackIp_TrickMode(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {BDBG_WRN(("Failed to do client side trickmodes ")); goto out;}
814        BDBG_WRN(("****************** FR Started ***************************"));
815            sleep(10);
816        if (B_PlaybackIp_Play(playbackIp)) {BDBG_ERR(("ERROR: Failed to resume from trickplay \n")); goto out;}
817    }
818        sleep(10);
819       
820    BDBG_WRN(("*******************************************************************************"));
821    BDBG_WRN(("****************** AUTO Test Completed Successfully ***************************"));
822    BDBG_WRN(("*******************************************************************************"));
823    return;
824
825out:
826    BDBG_WRN(("*******************************************************************************"));
827    BDBG_WRN(("***************************** AUTO Test Failed *********************************"));
828    BDBG_WRN(("*******************************************************************************"));
829    return;
830}
831
832/* logic to determine whether IP library should use Nexus Playpump to feed network stream or would it get pulled via Nexus Playback module */
833static bool
834useNexusPlaypumpForIpPlayback(
835    B_PlaybackIpPsiInfo *psi,
836    B_PlaybackIpProtocol protocol
837    )
838{
839    /* For RTP, UDP, RTSP based protocols, use Nexus Playpump as data is being pushed by the server and thus can't use the Nexus playback as it pulls data from IP library */
840    if (protocol != B_PlaybackIpProtocol_eHttp && protocol != B_PlaybackIpProtocol_eHttps) {
841        return true;
842    }
843
844    /* For HTTP/S, we can use both Nexus Playback or Playpump as it is a pull based protocol */
845
846    /* For following cases & protocols, we will use Nexus Playpump */
847    /* - Server side trickmodes are supported (either Playspeed or TimeSeekRange ) as Nexus playback can't maintain the stream position during trickplays */
848    /* - HLS protocol: stream segments are downloaded from server first and then feed into playpump */
849    /* - RVU protocol: is like Server supporting server side trickmodes, Nexus Playback can't track stream position during trickplays) */ 
850    if (psi->numPlaySpeedEntries > 1 /* DLNA App should use DLNA PS flags as well */ || psi->hlsSessionEnabled || psi->liveChannel) {
851        return true;
852    }
853
854    /* By default use the Nexus Playback for all protocols */
855    return false;
856}
857
858/* logic to determine which clock recorvery mechanism should be programmed for IP Playback Channels */
859static bool
860useLiveModeForIpPlayback(
861    B_PlaybackIpPsiInfo *psi,
862    B_PlaybackIpProtocol protocol,
863    B_PlaybackIpClockRecoveryMode *clockRecoveryModeForPlaybackIp
864    )
865{
866    bool useLiveIpMode;
867
868    /* psi discovery should be complete at this point, else we can't truly determine the clock mode and we default to pull mode */
869    if (!psi->psiValid) {
870        *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePull;
871        useLiveIpMode = false;
872    }
873
874    if (psi->mpegType != NEXUS_TransportType_eTs) {
875        /* for all non mpeg2 transport streams (ES, ASF, MP4, etc. formats), we are in the non-live mode */
876        /* as there is *no* good mechanism for locking to the sender's clock (TTS or PCRs are missing) */
877        /* this is true irrespective of the network protocol (HTTP vs. RTP/UDP) */
878        *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePull;
879        useLiveIpMode = false;
880    }
881    /* MPEG2 TS content */
882    else if (protocol != B_PlaybackIpProtocol_eHttp && protocol != B_PlaybackIpProtocol_eHttps) {
883        /* UDP, RTP, RTSP protocols carrying MPEG2 TS content are always put in live mode */
884        /* TODO: add call into IP library to determine if incoming stream is a TTS stream or not */
885        /* for now, use SyncSlipMode */
886        /* For DLNA Apps, media profile will indicate if it is a TTS or TS stream */
887        *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip;
888        useLiveIpMode = true;
889    }
890    /* MPEG2 TS content in HTTP/HTTPS protocols only */
891#if 0
892    /* RVU check */
893    else if (appCtx->rvuFlag) {
894        /* RVU protocol: channels are always in live mode whether live or files from disk are being streamed & have 4 byte Timestamps */
895        *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePushWithTtsNoSyncSlip;
896    }
897#endif
898    /* Non RVU MPEG2 TS content in HTTP/HTTPS protocols only */
899    else if (psi->liveChannel) {
900        /* special check to auto detect if this channel is in live mode (true for Broadcom servers as they send this flag) */
901        if (psi->transportTimeStampEnabled) {
902            /* live channel & stream has 4 byte Timestamps, use TTS based pacing mode */
903            *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePushWithTtsNoSyncSlip;
904            useLiveIpMode = true;
905        }
906        else {
907#if 1
908            /* live channel & stream doesn't has 4 byte Timestamps, so use PCRs as timestamps for pacing */
909            /* however, this PCR based basing is not yet fully tested, so default to pull mode for now */
910            *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePushWithPcrNoSyncSlip;
911            *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip;
912            useLiveIpMode = true;
913#else
914            *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePull;
915            useLiveIpMode = false;
916#endif
917        }
918    }
919    /* Non RVU MPEG2 TS content in HTTP/HTTPS protocols from non-Broadcom servers */
920    else {
921        /* App has to somehow to know whether this channel needs to be in Live or playback mode */
922        /* this could be based on either pre-defined channel map or from a DLNA level flag */
923        /* For DLNA apps, there is a VideoItem.VideoBroadcastItem flag indicates live mode */
924        /* then if the media profile is TTS, we can be in TTS mode. Else, when PCR pacing */
925        /* is supported, we can use PCR pacing mode. */
926        /* and default would be pull mode even though it is a live stream */
927
928        /* we default to pull mode */
929        *clockRecoveryModeForPlaybackIp = B_PlaybackIpClockRecoveryMode_ePull;
930        useLiveIpMode = false;
931    }
932
933    return useLiveIpMode;
934}
935
936static void sourceChangeCallback(void *context, int param)
937{
938    BSTD_UNUSED(context);
939    BDBG_WRN(("Got Source (%s) change callback", param ==1 ? "video" : "audio"));
940}
941
942static NEXUS_PlatformSettings platformSettings;
943int main(int argc, char *argv[])
944{
945    int i;
946    NEXUS_Error rc = NEXUS_UNKNOWN;
947    NEXUS_PlatformConfiguration platformConfig;
948    NEXUS_StcChannelHandle stcChannel;
949    NEXUS_TimebaseSettings timebaseSettings;
950    NEXUS_StcChannelSettings stcChannelSettings;
951    NEXUS_PidChannelHandle videoPidChannel = NULL, audioPidChannel = NULL, pcrPidChannel = NULL, extraVideoPidChannel = NULL;
952    NEXUS_PlaypumpSettings playpumpSettings;
953    NEXUS_PlaypumpHandle playpump = NULL;
954    NEXUS_PlaypumpOpenPidChannelSettings pidChannelSettings;
955    NEXUS_DisplayHandle display = NULL;
956    NEXUS_DisplaySettings displaySettings;
957    NEXUS_VideoWindowHandle window = NULL;
958    NEXUS_VideoDecoderHandle videoDecoder = NULL;
959    NEXUS_VideoDecoderOpenSettings videoDecoderOpenSettings;
960    NEXUS_VideoDecoderStartSettings videoProgram;
961    NEXUS_VideoDecoderSettings  videoDecoderSettings;
962    NEXUS_AudioDecoderOpenSettings audioDecoderOpenSettings;
963    NEXUS_AudioDecoderSettings audioDecoderSettings;
964    NEXUS_AudioOutputSettings audioOutputSettings;
965    NEXUS_AudioOutput output;
966    B_PlaybackIpOpenSettings playbackIpOpenSettings;
967    B_PlaybackIpSessionStartSettings ipSessionStartSettings;
968    B_PlaybackIpSessionStartStatus ipSessionStartStatus;
969    B_PlaybackIpSessionOpenSettings ipSessionOpenSettings;
970    B_PlaybackIpSessionOpenStatus ipSessionOpenStatus;
971    B_PlaybackIpSessionSetupSettings ipSessionSetupSettings;
972    B_PlaybackIpSessionSetupStatus ipSessionSetupStatus;
973    B_PlaybackIpHandle playbackIp = NULL;
974    NEXUS_PlaybackPidChannelSettings playbackPidChannelSettings;
975    NEXUS_VideoDecoderPrimerHandle primer[TOTAL_PRIMERS];
976
977    B_PlaybackIpTrickModesSettings ipTrickModeSettings;
978    B_PlaybackIpStatus playbackIpStatus;
979    B_PlaybackIpPsiInfo psi;
980    NEXUS_PlaybackHandle playback = NULL;
981    NEXUS_PlaybackSettings playbackSettings;
982    B_PlaybackIpSettings playbackIpSettings;
983    /* NEXUS_PlaybackStartSettings playbackStartSettings; */
984#if NEXUS_NUM_HDMI_OUTPUTS
985    NEXUS_HdmiOutputSettings hdmiSettings;
986#endif
987    char buf[16];
988    int numbytes;
989#ifdef B_AUTO_PSI_SUPPORT
990    psiCollectionDataType  collectionData;
991    int numPrograms;
992#endif
993    NEXUS_VideoDecoderStatus videoStatus;
994    NEXUS_AudioDecoderStatus audioStatus;
995    NEXUS_PlaybackStatus pbStatus;
996    NEXUS_PlaypumpStatus ppStatus;
997    uint32_t stc;
998#ifdef B_HAS_DTCP_IP
999    void * AkeHandle = NULL;
1000    void * dtcpCtx = NULL;
1001#endif
1002        NEXUS_DmaHandle dmaHandle;
1003    const bmedia_probe_track *track;
1004    const bmedia_probe_stream *stream;
1005   
1006#ifdef B_HAS_SSL
1007    void *ssl_ctx;
1008    B_PlaybackIpSslInitSettings sslInitSettings;
1009#endif
1010    NEXUS_PlaypumpOpenSettings playpumpOpenSettings;
1011#if NEXUS_HAS_SYNC_CHANNEL
1012    NEXUS_SyncChannelSettings syncChannelSettings;
1013    NEXUS_SyncChannelHandle syncChannel;
1014#endif
1015    B_PlaybackIpError rrc = 0; 
1016    NEXUS_VideoWindowScalerSettings scalerSettings;
1017
1018
1019    rrc = B_PlaybackIp_GetDefaultSettings(&playbackIpSettings);
1020    if (rrc !=B_ERROR_SUCCESS ) {
1021        BDBG_ERR((" Failed to initialize Playback IP Settings"));
1022        exit(1);
1023    }
1024
1025    if (ip_client_setup(argc, argv)) {
1026        exit(1);
1027    }
1028
1029    /* Dependencies: App must initialize OS lib */
1030    B_Os_Init();
1031
1032    if (!ipCfg.slaveMode) {
1033        /* Bring up all modules for a platform in a default configuration for this platform */
1034        NEXUS_Platform_GetDefaultSettings(&platformSettings);
1035        platformSettings.openFrontend = false;
1036#if NEXUS_DTV_PLATFORM
1037        platformSettings.displayModuleSettings.panel.lvds.lvdsMappingRule = NEXUS_PanelOutputMappingRule_eOpenLdiRule; 
1038        platformSettings.displayModuleSettings.panel.lvds.customLinkSettings.lvdsLinkMap1 = NEXUS_LvdsLinkMap_eInternalLink1;
1039        platformSettings.displayModuleSettings.panel.lvds.customLinkSettings.lvdsLinkMap2 = NEXUS_LvdsLinkMap_eInternalLink2;
1040        platformSettings.displayModuleSettings.panel.lvds.linkChannel[0].maskLinkHSync = 0;
1041        platformSettings.displayModuleSettings.panel.lvds.linkChannel[0].maskLinkVSync = 0;
1042        platformSettings.displayModuleSettings.panel.lvds.linkChannel[0].maskLinkDE    = 0;       
1043       
1044        platformSettings.displayModuleSettings.panel.lvds.linkChannel[1].maskLinkHSync = 0;
1045        platformSettings.displayModuleSettings.panel.lvds.linkChannel[1].maskLinkVSync = 0;
1046        platformSettings.displayModuleSettings.panel.lvds.linkChannel[1].maskLinkDE    = 0;
1047   
1048        if (strcmp("B552", getenv("panel_type")) == 0) {
1049            platformSettings.displayModuleSettings.panel.lvds.dvoLinkMode = NEXUS_PanelOutputLinkMode_eDualChannel1;
1050            platformSettings.displayModuleSettings.panel.lvds.lvdsColorMode = NEXUS_LvdsColorMode_e8Bit ;
1051            platformSettings.displayModuleSettings.panel.lvds.useNegativeEdge = false ;
1052   
1053            if (getenv("pixel_swap") != NULL && strcasecmp("yes", getenv("pixel_swap")) == 0) {
1054                platformSettings.displayModuleSettings.panel.lvds.dvoLinkMode = NEXUS_PanelOutputLinkMode_eCustom;
1055            }
1056        }
1057#endif
1058        rc = NEXUS_Platform_Init(&platformSettings);
1059    }
1060    else {
1061        rc = NEXUS_Platform_Join();
1062    }
1063    if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1064    NEXUS_Platform_GetConfiguration(&platformConfig);
1065
1066    if (BKNI_CreateEvent(&waitEvent)) { BDBG_ERR(("Failed to create an event at %d", __LINE__)); exit(1); }
1067
1068#if NEXUS_HAS_SYNC_CHANNEL
1069    if (!ipCfg.fastChannelChange) {
1070        /* create a sync channel */
1071        NEXUS_SyncChannel_GetDefaultSettings(&syncChannelSettings);
1072        syncChannelSettings.enablePrecisionLipsync = true;
1073        syncChannel = NEXUS_SyncChannel_Create(&syncChannelSettings);
1074        if (syncChannel == NULL) {BDBG_ERR(("NEXUS Error at %d, Exiting...\n", __LINE__)); exit(1);}
1075        BDBG_WRN(("Using Nexus STC channel for lipsync"));
1076    }
1077#endif
1078
1079    /* ----------------------------------------------------------------------------------------------------------------*/
1080    /* Open the StcChannel */
1081    NEXUS_StcChannel_GetDefaultSettings(0, &stcChannelSettings);
1082    stcChannelSettings.timebase = NEXUS_Timebase_e0;
1083    stcChannelSettings.mode = NEXUS_StcChannelMode_eAuto;
1084    stcChannel = NEXUS_StcChannel_Open(0, &stcChannelSettings);
1085    if (!stcChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1086    /* ----------------------------------------------------------------------------------------------------------------*/
1087
1088    /* ----------------------------------------------------------------------------------------------------------------*/
1089    /* Open Video decoder */
1090    NEXUS_VideoDecoder_GetDefaultOpenSettings(&videoDecoderOpenSettings);
1091    /* Increase the CDB size as it is used as the dejitter buffer */ 
1092    videoDecoderOpenSettings.fifoSize = 10 * 1024 * 1024;
1093    videoDecoder = NEXUS_VideoDecoder_Open(0, &videoDecoderOpenSettings);
1094    if (!videoDecoder) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1095    /* ----------------------------------------------------------------------------------------------------------------*/
1096
1097    /* ----------------------------------------------------------------------------------------------------------------*/
1098    /* Open & setup audio decoders and connect outputs */
1099    NEXUS_AudioDecoder_GetDefaultOpenSettings(&audioDecoderOpenSettings);
1100    BDBG_MSG(("fifo size %d, type %d\n", audioDecoderOpenSettings.fifoSize, audioDecoderOpenSettings.type));
1101    audioDecoderOpenSettings.fifoSize = 2*512 * 1024;
1102    audioDecoderOpenSettings.type = NEXUS_AudioDecoderType_eDecode;
1103    /*TODO: pcmDecoder = NEXUS_AudioDecoder_Open(0, &audioDecoderOpenSettings);*/
1104    /* */pcmDecoder = NEXUS_AudioDecoder_Open(0, NULL);
1105    if (!pcmDecoder) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1106
1107    /*compressedDecoder = NEXUS_AudioDecoder_Open(1, &audioDecoderOpenSettings);*/
1108    compressedDecoder = NEXUS_AudioDecoder_Open(1, NULL);
1109    if (!compressedDecoder) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1110
1111    /* ----------------------------------------------------------------------------------------------------------------*/
1112
1113
1114    /* ----------------------------------------------------------------------------------------------------------------*/
1115    /* Bring up video display and outputs */
1116    NEXUS_Display_GetDefaultSettings(&displaySettings);
1117#if NEXUS_DTV_PLATFORM
1118    /* Use default */
1119#else
1120    /* Note: change to display type back for panel output */
1121    displaySettings.displayType = NEXUS_DisplayType_eAuto;
1122    displaySettings.format = NEXUS_VideoFormat_e720p;
1123    displaySettings.format = NEXUS_VideoFormat_e1080i;
1124    displaySettings.format = NEXUS_VideoFormat_eNtsc;
1125    displaySettings.format = NEXUS_VideoFormat_e720p;
1126    BDBG_WRN(("Display format %d", displaySettings.format));
1127#endif
1128    display = NEXUS_Display_Open(0, &displaySettings);
1129    if (!display) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1130    /* ----------------------------------------------------------------------------------------------------------------*/
1131    /* ----------------------------------------------------------------------------------------------------------------*/
1132    window = NEXUS_VideoWindow_Open(display, 0);
1133    if (!window) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1134#if 0
1135    if (ipCfg.skipPsiParsing) {
1136        NEXUS_VideoWindowSettings windowSettings;
1137        /* is app is asking to skip psi parsing, we are lowering the window size */
1138        /* this is mainly done for the video conferencing demo case as we know the PSI info in advance and want to use smaller display window */
1139        NEXUS_VideoWindow_GetSettings(window, &windowSettings);
1140        windowSettings.position.x = 50 + (70 * 2);
1141        windowSettings.position.y = 50 + (30 * 2);
1142        windowSettings.position.width = 640/2;
1143        windowSettings.position.height = 480/2;
1144        NEXUS_VideoWindow_SetSettings(window, &windowSettings);
1145    }
1146#endif
1147#if NEXUS_DTV_PLATFORM
1148    NEXUS_Display_AddOutput(display, NEXUS_PanelOutput_GetConnector(platformConfig.outputs.panel[0]));
1149    NEXUS_BoardCfg_ConfigurePanel(true, true, true);
1150#else
1151#if NEXUS_NUM_COMPONENT_OUTPUTS
1152    rc = NEXUS_Display_AddOutput(display, NEXUS_ComponentOutput_GetConnector(platformConfig.outputs.component[0]));
1153    if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1154#endif
1155#if 0
1156    /* Note: enable for composite output */
1157#if NEXUS_NUM_COMPOSITE_OUTPUTS
1158    if ( platformConfig.outputs.composite[0] ) {
1159        rc = NEXUS_Display_AddOutput(display, NEXUS_CompositeOutput_GetConnector(platformConfig.outputs.composite[0]));
1160        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1161    }
1162#endif
1163#endif
1164#if NEXUS_NUM_HDMI_OUTPUTS
1165    /* Install hotplug callback -- video only for now */
1166    NEXUS_HdmiOutput_GetSettings(platformConfig.outputs.hdmi[0], &hdmiSettings);
1167    hdmiSettings.hotplugCallback.callback = hotplug_callback;
1168    hdmiSettings.hotplugCallback.context = platformConfig.outputs.hdmi[0];
1169    hdmiSettings.hotplugCallback.param = (int)display;
1170    NEXUS_HdmiOutput_SetSettings(platformConfig.outputs.hdmi[0], &hdmiSettings);
1171#endif
1172#endif
1173    BDBG_MSG(("Display Manager is Opened\n"));
1174
1175    /* connect video decoder to display */
1176    NEXUS_VideoWindow_AddInput(window, NEXUS_VideoDecoder_GetConnector(videoDecoder));
1177
1178#if NEXUS_NUM_HDMI_OUTPUTS
1179    /* Force a hotplug to check status */
1180    hotplug_callback(platformConfig.outputs.hdmi[0], (int)display);
1181#endif
1182
1183    /* ----------------------------------------------------------------------------------------------------------------*/
1184#ifdef B_HAS_SSL
1185    if (ipCfg.security == B_PlaybackIpSecurityProtocol_Ssl){
1186        memset(&sslInitSettings, 0, sizeof(B_PlaybackIpSslInitSettings)); 
1187        sslInitSettings.rootCaCertPath=CA_CERT;
1188        sslInitSettings.clientAuth=false;
1189        sslInitSettings.ourCertPath=NULL;
1190        sslInitSettings.privKeyPath=NULL;
1191        sslInitSettings.password=NULL;
1192        ssl_ctx = B_PlaybackIp_SslInit(&sslInitSettings);
1193        if (!ssl_ctx) {
1194            BDBG_ERR(("SSL Security initialization failed\n"));
1195            exit(1);
1196        }
1197    }
1198#endif
1199
1200        if ((dmaHandle = NEXUS_Dma_Open(0, NULL)) == NULL) {
1201        BDBG_ERR(("ERROR: NEXUS_Dma_Open failed"));
1202        return (-1);
1203    }
1204#ifdef B_HAS_DTCP_IP
1205    if (ipCfg.security == B_PlaybackIpSecurityProtocol_DtcpIp) {
1206        struct timeval t_start, t_finish;
1207
1208        /* initialize DtcpIp library */
1209        /* if App hasn't already opened the Nexus M2M DMA handle, then pass-in initial arg as NULL and let DTCP/IP library open the handle */
1210        if ((dtcpCtx = DtcpAppLib_Startup(B_DeviceMode_eSink, false)) == NULL) {
1211            BDBG_ERR(("ERROR: DtcpAppLib_Startup failed\n"));
1212            return (-1);
1213        }
1214        if(dtcpCtx == NULL)
1215        {
1216            BDBG_ERR(("%s: Failed to Initialize Dtcp/Ip Library: DTCP/IP encryption/decryption won't work\n", __FUNCTION__));
1217            exit(rc);
1218        }
1219#ifdef B_DTCP_IP_HW_DECRYPTION
1220        BDBG_MSG(("Initializing HW security params\n"));
1221        /* TODO: for VMS, we may need to pass in the nexus DMA handle here if it is already opened */
1222        if (DtcpInitHWSecurityParams(NULL) != BERR_SUCCESS) {
1223            BDBG_ERR(("ERROR: Failed to init DtcpHW Security parmas\n"));
1224            return (-1);
1225        }
1226#endif
1227
1228        /* Perform AKE for DTCP/IP */
1229        gettimeofday(&t_start, 0);
1230        BDBG_MSG(("host is %s, strlen %d\n", ipCfg.host, strlen(ipCfg.host)));
1231        if((rc = DtcpAppLib_DoAke(dtcpCtx, ipCfg.host, ipCfg.dtcpAkePort, &AkeHandle)) != BERR_SUCCESS) {
1232            BDBG_ERR(("DTCP AKE Failed!!!\n"));
1233            exit(rc);
1234        }
1235        gettimeofday(&t_finish, 0);
1236        BDBG_WRN(("-------------AKE took %d secs and %d msecs\n", 
1237            (t_finish.tv_usec < t_start.tv_usec? t_finish.tv_sec - t_start.tv_sec - 1: t_finish.tv_sec - t_start.tv_sec),
1238            (t_finish.tv_usec < t_start.tv_usec? t_finish.tv_usec - t_start.tv_usec + 1000000: t_finish.tv_usec - t_start.tv_usec) ));
1239    }
1240#endif
1241
1242#ifdef B_HAS_RAD_EA
1243    if (ipCfg.security == B_PlaybackIpSecurityProtocol_RadEa){
1244        B_PlaybackIp_RadEaInit(0);
1245    }
1246#endif
1247
1248    /* ----------------------------------------------------------------------------------------------------------------*/
1249    /* Open Nexus Playpump, For Live Modes, IP Applib directly feeds the network data to the Nexus Playpump */
1250    NEXUS_Playpump_GetDefaultOpenSettings(&playpumpOpenSettings);
1251    BDBG_WRN(("## fifo size %d, desc %d", playpumpOpenSettings.fifoSize, playpumpOpenSettings.numDescriptors));
1252    playpumpOpenSettings.fifoSize *= 2;
1253    playpumpOpenSettings.numDescriptors = 200;
1254    playpump = NEXUS_Playpump_Open(0, &playpumpOpenSettings);
1255    if (!playpump) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1256    NEXUS_Playpump_GetSettings(playpump, &playpumpSettings);
1257    /* IP Applib currently uses the FIFO mode to feed data, so app needs to set that mode */
1258    playpumpSettings.mode = NEXUS_PlaypumpMode_eFifo;
1259    rc = NEXUS_Playpump_SetSettings(playpump, &playpumpSettings);
1260    if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); goto error;}
1261    /* ----------------------------------------------------------------------------------------------------------------*/
1262
1263    /* ----------------------------------------------------------------------------------------------------------------*/
1264    /* Setup Nexus Playback, For Playback Modes (e.g. HTTP), IP Applib uses Nexus Playback to feed data */
1265    playback = NEXUS_Playback_Create();
1266    if (!playback) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1267    /* ----------------------------------------------------------------------------------------------------------------*/
1268
1269    /* ----------------------------------------------------------------------------------------------------------------*/
1270    /* Open IP Applib Handle */
1271    BDBG_MSG(("Initializing IP Applib...\n"));
1272    playbackIp = B_PlaybackIp_Open(&playbackIpOpenSettings);
1273    if (!playbackIp) {BDBG_WRN(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1274
1275newSession:
1276    gEventId = B_PlaybackIpEvent_eMax;
1277    /* ----------------------------------------------------------------------------------------------------------------*/
1278    /* Setup the security & socket setting structure used in the IP Session Open */
1279    memset(&ipSessionOpenSettings, 0, sizeof(ipSessionOpenSettings));
1280    memset(&ipSessionOpenStatus, 0, sizeof(ipSessionOpenStatus));
1281    /* Security */
1282    if (ipCfg.security > B_PlaybackIpSecurityProtocol_None) {
1283        switch (ipCfg.security ) {
1284#ifdef B_HAS_SSL
1285        case B_PlaybackIpSecurityProtocol_Ssl:
1286            ipSessionOpenSettings.security.securityProtocol = B_PlaybackIpSecurityProtocol_Ssl;
1287            ipSessionOpenSettings.security.initialSecurityContext = ssl_ctx;
1288            break;
1289#endif
1290#ifdef B_HAS_DTCP_IP
1291        /* DTCP-IP */
1292        case B_PlaybackIpSecurityProtocol_DtcpIp:
1293            ipSessionOpenSettings.security.securityProtocol = B_PlaybackIpSecurityProtocol_DtcpIp;
1294            ipSessionOpenSettings.security.initialSecurityContext = AkeHandle;
1295            break;
1296#endif
1297        case B_PlaybackIpSecurityProtocol_Aes128:
1298            BDBG_WRN(("Setting the dma handle for HLS encryption"));
1299            ipSessionOpenSettings.security.securityProtocol = B_PlaybackIpSecurityProtocol_Aes128;
1300            ipSessionOpenSettings.security.initialSecurityContext = dmaHandle;
1301            break;
1302        /* TODO RAD-EA */
1303        default:
1304            BDBG_ERR(("TODO: Security options\n"));
1305            break;
1306        }
1307    }
1308    else
1309        /* just pass the dma handle to IP library in case it needs it */
1310       ipSessionOpenSettings.security.initialSecurityContext = dmaHandle;
1311
1312    /* Set IP Address, Port, and Protocol used to receive the AV stream */
1313    strncpy(ipSessionOpenSettings.socketOpenSettings.ipAddr, ipCfg.host, sizeof(ipSessionOpenSettings.socketOpenSettings.ipAddr)-1);
1314    ipSessionOpenSettings.socketOpenSettings.port = atoi(ipCfg.port);
1315    ipSessionOpenSettings.socketOpenSettings.protocol = ipCfg.protocol;
1316    memset(&psi, 0, sizeof(psi));
1317    switch (ipCfg.protocol) {
1318    case B_PlaybackIpProtocol_eUdp:
1319    case B_PlaybackIpProtocol_eRtpNoRtcp:
1320    case B_PlaybackIpProtocol_eRtp:
1321        ipSessionOpenSettings.ipMode = B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip;
1322        ipSessionOpenSettings.maxNetworkJitter = 300;
1323        ipSessionOpenSettings.networkTimeout = 1;  /* timeout in 1 sec during network outage events */
1324        rc = B_PlaybackIp_SessionOpen(playbackIp, &ipSessionOpenSettings, &ipSessionOpenStatus);
1325        if (rc) {
1326            BDBG_ERR(("Session Open call failed: rc %d", rc));
1327            goto errorClose;
1328        }
1329        BDBG_WRN(("Session Open call succeeded"));
1330        break;
1331    case B_PlaybackIpProtocol_eRtsp:
1332        ipSessionOpenSettings.ipMode = B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip;
1333        ipSessionOpenSettings.maxNetworkJitter = 300;
1334        ipSessionOpenSettings.networkTimeout = 1;  /* timeout in 1 sec during network outage events */
1335        ipSessionOpenSettings.socketOpenSettings.protocol = B_PlaybackIpProtocol_eRtsp;
1336        ipSessionOpenSettings.socketOpenSettings.url = ipCfg.url;
1337        /* App can set this flag to enable non-blocking mode of IP library APIs */
1338        /* ipSessionOpenSettings.nonBlockingMode = true;*/
1339        ipSessionOpenSettings.nonBlockingMode = true;
1340        ipSessionOpenSettings.eventCallback = playbackIpEventCallback;
1341        ipSessionOpenSettings.appCtx = playbackIp; /* this should be app handle */
1342        /* apps can request IP library to return the RTSP Response Message incase it needs to extract any custom headers */
1343        ipSessionOpenSettings.u.rtsp.copyResponseHeaders = true;
1344        rc = B_PlaybackIp_SessionOpen(playbackIp, &ipSessionOpenSettings, &ipSessionOpenStatus);
1345        if (rc == B_ERROR_IN_PROGRESS) {
1346            /* app can do some useful work while SessionOpen is in progress and resume when callback sends the completion event */
1347            BDBG_WRN(("Session Open call in progress, sleeping for now..."));
1348            while (gEventId != B_PlaybackIpEvent_eSessionOpenDone)
1349                /* Note: instead of while loop, app can just wait on an event which is signalled by the callback function */
1350                BKNI_Sleep(100);
1351            /* So we got the event, call SessionOpen again to retrieve the session open status */
1352            rc = B_PlaybackIp_SessionOpen(playbackIp, &ipSessionOpenSettings, &ipSessionOpenStatus);
1353        }
1354        if (rc != B_ERROR_SUCCESS) {
1355            BDBG_ERR(("Socket Open call failed: rc %d, HTTP Status %d\n", rc, ipSessionOpenStatus.u.rtsp.statusCode));
1356            goto errorClose;
1357        }
1358        BDBG_WRN(("Session Open call succeeded, RTSP status code %d", ipSessionOpenStatus.u.rtsp.statusCode));
1359        memset(&ipSessionSetupSettings, 0, sizeof(ipSessionSetupSettings));
1360        ipSessionSetupSettings.u.rtsp.userAgent = "Broadcom's LiveMedia based test RTSP Client";
1361        /* apps can request IP library to return the RTSP Response Message incase it needs to extract any custom headers */
1362        ipSessionSetupSettings.u.rtsp.copyResponseHeaders = true;
1363        /* Note: can optionally set the additionalHeaders field */
1364        rc = B_PlaybackIp_SessionSetup(playbackIp, &ipSessionSetupSettings, &ipSessionSetupStatus);
1365        BKNI_ResetEvent(waitEvent);
1366        if (rc == B_ERROR_IN_PROGRESS) {
1367            BERR_Code err;
1368            /* app can do some useful work while SessionSetup is in progress and resume when callback sends the completion event */
1369            BDBG_WRN(("Session Setup call in progress, sleeping for now..."));
1370            err = BKNI_WaitForEvent(waitEvent, EVENT_WAIT_TIME_IN_MSEC);
1371            if (err == BERR_TIMEOUT || err != 0) {
1372                BDBG_WRN(("Session Setup call timed out or got error (err %d)!!!", err));
1373                goto error;
1374            }
1375            /* So we got the event, call SessionSetup again to retrieve the session setup status (psi & file handle) */
1376            rc = B_PlaybackIp_SessionSetup(playbackIp, &ipSessionSetupSettings, &ipSessionSetupStatus);
1377        }
1378        if (rc != B_ERROR_SUCCESS) {
1379            BDBG_ERR(("Session Setup call failed: rc %d\n", rc));
1380            goto error;
1381        }
1382        for (i=0; i<ipSessionSetupStatus.u.rtsp.scaleListEntries; i++)
1383            BDBG_MSG(("scale list[%d] = %0.1f", ipSessionSetupStatus.u.rtsp.scaleList[i]));
1384        break;
1385    case B_PlaybackIpProtocol_eHttp:
1386        ipSessionOpenSettings.socketOpenSettings.protocol = B_PlaybackIpProtocol_eHttp;
1387        ipSessionOpenSettings.ipMode = B_PlaybackIpClockRecoveryMode_ePull;
1388        ipSessionOpenSettings.networkTimeout = 1;  /* timeout in 1 sec during network outage events */
1389#if 0
1390        /* set this flag is App already knows the PSI info of the stream and it wants to use Nexus Playpump for feeding IP session data */
1391        ipSessionOpenSettings.useNexusPlaypump = 1;
1392#endif
1393        ipSessionOpenSettings.u.http.networkBufferSize = (30*3*1024*1024)/8; /* data cache size: 30sec worth for a max bitrate of 3Mbps */
1394        ipSessionOpenSettings.socketOpenSettings.url = ipCfg.url;
1395        /* If app needs to set any addition HTTP header fields that need to be sent in the outgoing HTTP Get request */
1396        /* they should be set in additionalHttpHeaderFields strings. E.g. for DLNA requests, app can specify the desired transfer mode */
1397        ipSessionOpenSettings.u.http.additionalHeaders = "Cookie: VISITOR_INFO1_LIVE=mRUZ7HDi4Yc;\r\n";
1398        ipSessionOpenSettings.u.http.additionalHeaders = "transferMode.dlna.org: Streaming\r\n";   /* Streaming mode for AV content */
1399        /* apps can override the default user agent string in the outgoing HTTP Get Request */
1400        ipSessionOpenSettings.u.http.userAgent = "BRCM IP Applib Test App/2.0";
1401        /* apps can request IP library to return the HTTP Response Message incase it needs to extract any custom headers */
1402        ipSessionOpenSettings.u.http.copyResponseHeaders = true;
1403        /* setup a callback for receiving various events from IP library */
1404        ipSessionOpenSettings.eventCallback = playbackIpEventCallback;
1405        ipSessionOpenSettings.appCtx = playbackIp; /* this should be app handle */
1406        /* App can set this flag to enable non-blocking mode of IP library APIs */
1407        /* ipSessionOpenSettings.nonBlockingMode = true;*/
1408        ipSessionOpenSettings.nonBlockingMode = true;
1409        ipSessionOpenSettings.eventCallback = playbackIpEventCallback;
1410        rc = B_PlaybackIp_SessionOpen(playbackIp, &ipSessionOpenSettings, &ipSessionOpenStatus);
1411        if (rc == B_ERROR_IN_PROGRESS) {
1412            /* app can do some useful work while SessionOpen is in progress and resume when callback sends the completion event */
1413            BDBG_WRN(("Session Open call in progress, sleeping for now..."));
1414            while (gEventId != B_PlaybackIpEvent_eSessionOpenDone)
1415                /* Note: instead of while loop, app can just wait on an event which is signalled by the callback function */
1416                BKNI_Sleep(100);
1417            /* So we got the event, call SessionOpen again to retrieve the session open status */
1418            rc = B_PlaybackIp_SessionOpen(playbackIp, &ipSessionOpenSettings, &ipSessionOpenStatus);
1419        }
1420        if (rc != B_ERROR_SUCCESS) {
1421            BDBG_ERR(("Session Open call failed: rc %d, HTTP Status %d\n", rc, ipSessionOpenStatus.u.http.statusCode));
1422            goto errorClose;
1423        }
1424        BDBG_WRN(("Session Open call succeeded, HTTP status code %d", ipSessionOpenStatus.u.http.statusCode));
1425        if (ipSessionOpenStatus.u.http.responseHeaders) {
1426            BDBG_MSG(("Response Header is... \n%s", ipSessionOpenStatus.u.http.responseHeaders));
1427            /* Note: App can extract any customer Response Headers here: useful to extract DLNA flags from getContentFeatures Header */
1428
1429            /* now free the responseHeader */
1430            free(ipSessionOpenStatus.u.http.responseHeaders);
1431        }
1432        memset(&ipSessionSetupSettings, 0, sizeof(ipSessionSetupSettings));
1433        /* If app knows the media container type, then it can provide the hint to IP Applib */
1434        /*ipSessionSetupSettings.contentTypeHint = NEXUS_TransportType_eEs; */
1435        if (ipCfg.playMp3) {
1436            BDBG_WRN(("Playing Mp3, so tell IP Applib to skip auto PSI probing\n"));
1437            ipSessionSetupSettings.u.http.skipPsiParsing = false;
1438            ipSessionSetupSettings.u.http.avgBitRate = 192000;
1439            ipSessionSetupSettings.u.http.contentLengthHint = 2182835;
1440        }
1441        else if (ipCfg.playLpcm) {
1442            BDBG_WRN(("Playing LPCM, so tell IP Applib to skip auto PSI probing & Convert LPCM to WAV by inserting WAV header\n"));
1443            ipSessionSetupSettings.u.http.skipPsiParsing = true;
1444            ipSessionSetupSettings.u.http.avgBitRate = 192000; /* please set it if known */
1445            ipSessionSetupSettings.u.http.convertLpcmToWave = true;
1446            ipSessionSetupSettings.u.http.bitsPerSample = 16;
1447            ipSessionSetupSettings.u.http.sampleRate = 48000;
1448            ipSessionSetupSettings.u.http.numChannels = 2;
1449        }
1450#if 0
1451        /* If app figures out from getContentFeatures that the server doesn't support HTTP Range Headers, then it can set a flag to tell IP Applib to not include one in outgoing Get Req */
1452        ipSessionSetupSettings.u.http.disableRangeHeader = true;
1453        /* since Range header is not supported by server, then we can't seek to it and thus tell IP library to disable trick modes */
1454        ipSessionSetupSettings.u.http.dontUseIndex = true;
1455#endif
1456
1457        /* if app needs to play multiple formats (such as a DLNA DMP/DMR) (e.g. TS, VOB/PES), then set this option to do deep payload inspection */
1458        ipSessionSetupSettings.u.http.enablePayloadScanning = true;
1459
1460        rc = B_PlaybackIp_SessionSetup(playbackIp, &ipSessionSetupSettings, &ipSessionSetupStatus);
1461        if (rc == B_ERROR_IN_PROGRESS) {
1462            BERR_Code err;
1463            /* app can do some useful work while SessionSetup is in progress and resume when callback sends the completion event */
1464            BDBG_WRN(("Session Setup call in progress, sleeping for now..."));
1465            err = BKNI_WaitForEvent(waitEvent, EVENT_WAIT_TIME_IN_MSEC);
1466            if (err == BERR_TIMEOUT || err != 0) {
1467                BDBG_WRN(("Session Setup call timed out or got error (err %d)!!!", err));
1468                goto errorClose;
1469            }
1470            /* So we got the event, call SessionSetup again to retrieve the session setup status (psi & file handle) */
1471            rc = B_PlaybackIp_SessionSetup(playbackIp, &ipSessionSetupSettings, &ipSessionSetupStatus);
1472        }
1473        if (rc != B_ERROR_SUCCESS) {
1474            BDBG_ERR(("Session Setup call failed: rc %d\n", rc));
1475            goto error;
1476        }
1477        psi = ipSessionSetupStatus.u.http.psi;
1478        BDBG_WRN(("Session Setup call succeeded, file handle %p", ipSessionSetupStatus.u.http.file));
1479        if (ipSessionSetupSettings.u.http.skipPsiParsing) 
1480            goto skipTrackInfo;
1481        stream = (bmedia_probe_stream *)(ipSessionSetupStatus.u.http.stream);
1482        if (!stream)
1483            goto skipTrackInfo;
1484        for (track=BLST_SQ_FIRST(&stream->tracks);track;track=BLST_SQ_NEXT(track, link)) {
1485            if (track->type==bmedia_track_type_video) {
1486                BDBG_MSG(("video track %u codec:%u\n", track->number, track->info.video.codec));
1487            }
1488            if (track->type==bmedia_track_type_pcr) {
1489                BDBG_MSG(("pcr pid %u\n", track->number));
1490            }
1491            else if(track->type==bmedia_track_type_audio) {
1492                BDBG_MSG(("audio track %u codec:%u\n", track->number, track->info.audio.codec));
1493            }
1494        }
1495skipTrackInfo:
1496        break;
1497    default:
1498        BDBG_WRN(("Protocol %d not supported", ipCfg.protocol));
1499        goto error;
1500    }
1501
1502    /* ----------------------------------------------------------------------------------------------------------------*/
1503    BDBG_MSG(("IP SessionOpen Complete"));
1504
1505    if (ipCfg.playMp3) {
1506        psi.psiValid = true;
1507        psi.audioCodec = NEXUS_AudioCodec_eMp3;
1508        psi.audioPid = 0x1;
1509        psi.mpegType = NEXUS_TransportType_eEs;
1510    }
1511    else if (ipCfg.playLpcm) {
1512        psi.psiValid = true;
1513        psi.audioCodec = NEXUS_AudioCodec_ePcmWav;
1514        psi.audioPid = 0x1;
1515        psi.mpegType = NEXUS_TransportType_eWav;
1516    }
1517    /* ----------------------------------------------------------------------------------------------------------------*/
1518    else if (ipCfg.skipPsiParsing) {
1519        /* hardcode the codec info */
1520        /* current one is for Video Conferencing Demo case where camera output is being streamed to us via RTP */
1521        memset(&psi, 0, sizeof(psi));
1522        psi.psiValid = true;
1523        psi.videoCodec = NEXUS_VideoCodec_eMpeg4Part2;
1524        psi.videoCodec = NEXUS_VideoCodec_eH264;
1525        psi.videoPid = 0x1;
1526        psi.audioPid = 0;
1527        psi.pcrPid = 0x1;
1528        psi.mpegType = NEXUS_TransportType_eEs;
1529    }
1530#ifdef B_AUTO_PSI_SUPPORT
1531    else if (psi.psiValid == false) {
1532        /* For non-HTTP protocols, apps will need to use psip library to do the psi discovery */
1533        memset(&collectionData, 0, sizeof(psiCollectionDataType));
1534        collectionData.playpump = playpump;
1535        collectionData.live = true;
1536        collectionData.playbackIp = playbackIp;
1537        BDBG_WRN(("Acquiring PSI info..."));
1538        acquirePsiInfo(&collectionData,  &psi, &numPrograms);
1539    }
1540#endif
1541
1542    /* ----------------------------------------------------------------------------------------------------------------*/
1543    /* If IP Applib is not able to find the PSI info, then set them to defaults */
1544    if (psi.psiValid == false) setDefaultPsiSettings(&psi);
1545   
1546    BDBG_WRN(("Video Pid %d, Video Codec %d, Audio Pid %d, Audio Codec %d, Pcr Pid %d, Transport Type %d", 
1547                psi.videoPid, psi.videoCodec, psi.audioPid, psi.audioCodec, psi.pcrPid, psi.mpegType));
1548
1549    if (psi.hlsSessionEnabled) {
1550        NEXUS_VideoWindow_GetScalerSettings(window, &scalerSettings);
1551        scalerSettings.bandwidthEquationParams.bias = NEXUS_ScalerCaptureBias_eScalerBeforeCapture;
1552        scalerSettings.bandwidthEquationParams.delta = 1*1000*1000;
1553        rc = NEXUS_VideoWindow_SetScalerSettings(window, &scalerSettings);
1554        BDBG_ASSERT(!rc);
1555        BDBG_WRN(("HLS Session: Updated Scaler settings to fix Scaler before Capture"));
1556    }
1557
1558    /* ----------------------------------------------------------------------------------------------------------------*/
1559
1560    if (ipCfg.fastChannelChange) {
1561        for (i=0;i<TOTAL_PRIMERS;i++) {
1562            primer[i] = NEXUS_VideoDecoder_OpenPrimer(videoDecoder);
1563        }
1564    }
1565
1566    B_PlaybackIp_GetSettings(playbackIp, &playbackIpSettings);
1567    ipCfg.useLiveIpMode = useLiveModeForIpPlayback(&psi, ipCfg.protocol, &playbackIpSettings.ipMode);
1568    playbackIpSettings.useNexusPlaypump = useNexusPlaypumpForIpPlayback(&psi, ipCfg.protocol);
1569        if (playbackIpSettings.ipMode == B_PlaybackIpClockRecoveryMode_ePushWithTtsNoSyncSlip) {
1570            playbackIpSettings.ttsParams.autoDetect = false;
1571            playbackIpSettings.ttsParams.pacingMaxError = 2636;
1572            playbackIpSettings.ttsParams.throttleParams.initBufDepth = 625000;
1573            playbackIpSettings.ttsParams.throttleParams.maxBufDepth = 2250000;
1574            playbackIpSettings.ttsParams.throttleParams.minBufDepth = 125000;
1575            playbackIpSettings.ttsParams.throttleParams.maxClockMismatch = 60;
1576        }
1577    rc = B_PlaybackIp_SetSettings(playbackIp, &playbackIpSettings);
1578    if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); return (-1);}
1579    BDBG_WRN(("IP Clock Recovery Mode set to %s Mode (%d), using Nexus %s to feed stream over IP", 
1580                playbackIpSettings.ipMode == B_PlaybackIpClockRecoveryMode_ePull? "non-Live":"Live", playbackIpSettings.ipMode,
1581                playbackIpSettings.useNexusPlaypump? "Playpump" : "Playback"));
1582
1583    /* do the initial configuration of Nexus Playpump/Playback modules: set modes & open pid channels */
1584    if (playbackIpSettings.useNexusPlaypump) {
1585        NEXUS_Playpump_GetSettings(playpump, &playpumpSettings);
1586        playpumpSettings.transportType = psi.mpegType;
1587        if (playbackIpSettings.ipMode == B_PlaybackIpClockRecoveryMode_ePushWithTtsNoSyncSlip) {
1588            playpumpSettings.timestamp.type = NEXUS_TransportTimestampType_eBinary;
1589            playpumpSettings.timestamp.timebase = NEXUS_Timebase_e1;
1590            playpumpSettings.timestamp.pacingMaxError = playbackIpSettings.ttsParams.pacingMaxError;
1591            playpumpSettings.timestamp.pacing = true;
1592            playpumpSettings.timestamp.pacingOffsetAdjustDisable = true;
1593            playpumpSettings.timestamp.parityCheckDisable = true;
1594            playpumpSettings.timestamp.resetPacing = true;
1595            BDBG_WRN(("$$$$$$$$$$$$$$$$$ updated TTS related params for playpump ...."));
1596        }
1597        rc = NEXUS_Playpump_SetSettings(playpump, &playpumpSettings);
1598        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); goto error;}
1599
1600        /* Open the video pid channel */
1601        if (psi.videoPid) {
1602            NEXUS_Playpump_GetDefaultOpenPidChannelSettings(&pidChannelSettings);
1603            pidChannelSettings.pidType = NEXUS_PidType_eVideo;
1604            videoPidChannel = NEXUS_Playpump_OpenPidChannel(playpump, psi.videoPid, &pidChannelSettings);
1605            if (!videoPidChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1606        }
1607
1608        /* Open the extra video pid channel if present in the stream */
1609        if (psi.extraVideoCodec != NEXUS_VideoCodec_eNone && psi.extraVideoPid != 0) {
1610            NEXUS_Playpump_GetDefaultOpenPidChannelSettings(&pidChannelSettings);
1611            pidChannelSettings.pidType = NEXUS_PidType_eVideo;
1612            extraVideoPidChannel = NEXUS_Playpump_OpenPidChannel(playpump, psi.extraVideoPid, &pidChannelSettings);
1613            if (!extraVideoPidChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1614            BDBG_WRN(("%s: extra video pid %d, codec %d is present, pid channel created", __FUNCTION__, psi.extraVideoPid, psi.extraVideoCodec));
1615        }
1616
1617        if (psi.audioPid) {
1618            /* Open the audio pid channel */
1619            NEXUS_Playpump_GetDefaultOpenPidChannelSettings(&pidChannelSettings);
1620            pidChannelSettings.pidType = NEXUS_PidType_eAudio;
1621            pidChannelSettings.pidTypeSettings.audio.codec = psi.audioCodec;
1622            audioPidChannel = NEXUS_Playpump_OpenPidChannel(playpump, psi.audioPid, &pidChannelSettings);
1623            if (!audioPidChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1624        }
1625
1626        if (psi.pcrPid != psi.audioPid && psi.pcrPid != psi.videoPid) {
1627            /* Open the pcr pid channel */
1628            NEXUS_Playpump_GetDefaultOpenPidChannelSettings(&pidChannelSettings);
1629            pidChannelSettings.pidType = NEXUS_PidType_eUnknown;
1630            pcrPidChannel = NEXUS_Playpump_OpenPidChannel(playpump, psi.pcrPid, &pidChannelSettings);
1631            if (!pcrPidChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1632        }
1633        else 
1634            pcrPidChannel = videoPidChannel;
1635    }
1636    else {
1637        /* using Nexus Playback module */
1638        NEXUS_Playback_GetSettings(playback, &playbackSettings);
1639        playbackSettings.playpump = playpump;
1640        if (psi.videoPid) 
1641            playbackSettings.stcChannel = stcChannel;
1642        if (ipCfg.initialSeekTime || ipCfg.preChargeTime)
1643            playbackSettings.startPaused = true;
1644        if (!ipCfg.loop) {
1645            playbackSettings.endOfStreamCallback.callback = endOfStreamCallback;
1646            playbackSettings.endOfStreamCallback.context = NULL;
1647            playbackSettings.errorCallback.callback = errorCallback;
1648            playbackSettings.errorCallback.context = NULL;
1649            playbackSettings.endOfStreamAction = NEXUS_PlaybackLoopMode_ePause;
1650        }
1651        else {
1652            playbackSettings.endOfStreamAction = NEXUS_PlaybackLoopMode_eLoop;
1653        }
1654        if (ipCfg.playMp3 || ipCfg.playLpcm || psi.audioCodec == NEXUS_AudioCodec_eMp3) {
1655            BDBG_WRN(("Enabling streamProcessing flag for audio seeking capability"));
1656            playbackSettings.enableStreamProcessing = true; /* needed for seek capability */
1657        }
1658        playbackSettings.playpumpSettings.transportType = psi.mpegType;
1659        playbackSettings.playpumpSettings.mode = NEXUS_PlaypumpMode_eFifo;
1660        if (psi.transportTimeStampEnabled) {
1661            playbackSettings.playpumpSettings.timestamp.type = NEXUS_TransportTimestampType_eMod300;
1662            playbackSettings.playpumpSettings.timestamp.pacing = false;
1663            BDBG_WRN(("Setting timestamp flag"));
1664        }
1665        rc = NEXUS_Playback_SetSettings(playback, &playbackSettings);
1666        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1667        /* TODO: type setting following:
1668            playbackStartSettings.mode = NEXUS_PlaybackMode_eAutoBitrate;
1669        */
1670
1671        if (psi.videoPid) {
1672            NEXUS_Playback_GetDefaultPidChannelSettings(&playbackPidChannelSettings);
1673            playbackPidChannelSettings.pidSettings.pidType = NEXUS_PidType_eVideo;
1674            playbackPidChannelSettings.pidTypeSettings.video.codec = psi.videoCodec;
1675            playbackPidChannelSettings.pidTypeSettings.video.decoder = videoDecoder;        /* Decode will set this later */
1676            playbackPidChannelSettings.pidTypeSettings.video.index = true;
1677            videoPidChannel = NEXUS_Playback_OpenPidChannel(playback, psi.videoPid, &playbackPidChannelSettings);
1678            if (!videoPidChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1679        }
1680
1681        /* Open the extra video pid channel if present in the stream */
1682        if (psi.extraVideoCodec != NEXUS_VideoCodec_eNone && psi.extraVideoPid != 0) {
1683            NEXUS_Playback_GetDefaultPidChannelSettings(&playbackPidChannelSettings);
1684            playbackPidChannelSettings.pidSettings.pidType = NEXUS_PidType_eVideo;
1685            playbackPidChannelSettings.pidTypeSettings.video.codec = psi.extraVideoCodec;
1686            playbackPidChannelSettings.pidTypeSettings.video.decoder = videoDecoder;        /* Decode will set this later */
1687            playbackPidChannelSettings.pidTypeSettings.video.index = true;
1688            extraVideoPidChannel = NEXUS_Playback_OpenPidChannel(playback, psi.extraVideoPid, &playbackPidChannelSettings);
1689            if (!extraVideoPidChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1690            BDBG_WRN(("%s: extra video pid %d, codec %d is present, pid channel created", __FUNCTION__, psi.extraVideoPid, psi.extraVideoCodec));
1691        }
1692
1693        if (psi.audioPid) {
1694            NEXUS_Playback_GetDefaultPidChannelSettings(&playbackPidChannelSettings);
1695            playbackPidChannelSettings.pidSettings.pidType = NEXUS_PidType_eAudio;
1696            playbackPidChannelSettings.pidSettings.pidTypeSettings.audio.codec = psi.audioCodec;
1697            playbackPidChannelSettings.pidTypeSettings.audio.primary = pcmDecoder;
1698            audioPidChannel = NEXUS_Playback_OpenPidChannel(playback, psi.audioPid, &playbackPidChannelSettings);
1699            if (!audioPidChannel) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1700            BDBG_MSG(("Playback Audio Pid channel is opened\n"));
1701        }
1702    }
1703    /* ----------------------------------------------------------------------------------------------------------------*/
1704
1705    /* ----------------------------------------------------------------------------------------------------------------*/
1706    /* Stc Channel configuration */
1707    NEXUS_StcChannel_GetSettings(stcChannel, &stcChannelSettings);
1708    switch (playbackIpSettings.ipMode) {
1709    case B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip:
1710        /* Following Nexus configuration is done for absorbing high IP network jitter
1711         -DPCR & PCR Offset blocks are programmed w/ increased thresholds for errors
1712         -Both display & audio outputs are decoupled from input time base & run from a free clock
1713         -AV CDBs sizes are increased to absorb the network jitter
1714         -AV decodes are delayed by the amount of jitter buffer depth
1715        */
1716        if (psi.pcrPid) {
1717            /* program the timebase 0: increase its track range & max pcr errors */
1718            NEXUS_Timebase_GetSettings(NEXUS_Timebase_e0, &timebaseSettings);
1719            timebaseSettings.sourceType = NEXUS_TimebaseSourceType_ePcr;
1720            timebaseSettings.freeze = false;
1721            timebaseSettings.sourceSettings.pcr.pidChannel = pcrPidChannel;
1722            timebaseSettings.sourceSettings.pcr.maxPcrError = IP_NETWORK_JITTER * 183/2;    /* in milliseconds: based on 90Khz clock */
1723            timebaseSettings.sourceSettings.pcr.trackRange = NEXUS_TimebaseTrackRange_e244ppm;
1724            rc = NEXUS_Timebase_SetSettings(NEXUS_Timebase_e0, &timebaseSettings);
1725            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1726            BDBG_WRN(("Configured Timebase %d with jitter %d", NEXUS_Timebase_e0, IP_NETWORK_JITTER));
1727
1728            /* Update STC Channel Settings to accomodate Network Jitter */
1729            /* configure the StcChannel to do lipsync with the PCR */
1730            stcChannelSettings.timebase = NEXUS_Timebase_e0;     /* timebase */
1731            stcChannelSettings.mode = NEXUS_StcChannelMode_ePcr; /* Live Mode */
1732            /* offset threshold: uses upper 32 bits (183ticks/msec) of PCR clock */
1733            stcChannelSettings.modeSettings.pcr.offsetThreshold = IP_NETWORK_JITTER * 183; 
1734            /* max pcr error: uses upper 32 bits (183ticks/msec) of PCR clock */
1735            stcChannelSettings.modeSettings.pcr.maxPcrError =  IP_NETWORK_JITTER * 183;
1736            stcChannelSettings.modeSettings.pcr.pidChannel = pcrPidChannel;
1737            /*  PCR Offset "Jitter Adjustment" is not suitable for use with IP channels Channels, so disable it */
1738            stcChannelSettings.modeSettings.pcr.disableJitterAdjustment = true;
1739            /* Disable Auto Timestamp correction for PCR Jitter */
1740            stcChannelSettings.modeSettings.pcr.disableTimestampCorrection = true;
1741            /* We just configured the Timebase, so turn off auto timebase config */
1742            stcChannelSettings.autoConfigTimebase = false;
1743            BDBG_WRN(("Configured stc channel: timebase %d, jitter %d", NEXUS_Timebase_e0, IP_NETWORK_JITTER));
1744        }
1745
1746        /* Setup timebase 1 to free run */
1747        NEXUS_Timebase_GetSettings(NEXUS_Timebase_e1, &timebaseSettings);
1748        timebaseSettings.freeze = true;
1749        timebaseSettings.sourceSettings.pcr.trackRange = NEXUS_TimebaseTrackRange_e61ppm;
1750        timebaseSettings.sourceType = NEXUS_TimebaseSourceType_eFreeRun;
1751        rc = NEXUS_Timebase_SetSettings(NEXUS_Timebase_e1, &timebaseSettings);
1752        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1753        BDBG_MSG(("Configured Timebase %d to freerun \n", NEXUS_Timebase_e1));
1754        break;
1755
1756    case B_PlaybackIpClockRecoveryMode_ePushWithTtsNoSyncSlip:
1757    case B_PlaybackIpClockRecoveryMode_ePushWithPcrNoSyncSlip:
1758        if (psi.pcrPid) {
1759            /* program the timebase 0: increase its track range & max pcr errors */
1760            NEXUS_Timebase_GetSettings(NEXUS_Timebase_e0, &timebaseSettings);
1761            timebaseSettings.sourceType = NEXUS_TimebaseSourceType_ePcr;
1762            timebaseSettings.freeze = false;
1763            timebaseSettings.sourceSettings.pcr.pidChannel = pcrPidChannel;
1764            timebaseSettings.sourceSettings.pcr.maxPcrError = 255;
1765            timebaseSettings.sourceSettings.pcr.trackRange = NEXUS_TimebaseTrackRange_e61ppm;
1766            rc = NEXUS_Timebase_SetSettings(NEXUS_Timebase_e0, &timebaseSettings);
1767            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1768            BDBG_MSG(("Configured Timebase %d with increased tracking range & maxPcrError \n", NEXUS_Timebase_e0));
1769
1770        }
1771        else {
1772            /* program the timebase 0: increase its track range & max pcr errors */
1773            NEXUS_Timebase_GetSettings(NEXUS_Timebase_e0, &timebaseSettings);
1774            timebaseSettings.sourceType = NEXUS_TimebaseSourceType_eFreeRun;
1775            timebaseSettings.freeze = true;
1776            timebaseSettings.sourceSettings.freeRun.trackRange = NEXUS_TimebaseTrackRange_e61ppm;
1777            timebaseSettings.sourceSettings.freeRun.centerFrequency = 0x400000;
1778            rc = NEXUS_Timebase_SetSettings(NEXUS_Timebase_e0, &timebaseSettings);
1779            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1780            BDBG_MSG(("Configured Timebase %d with increased tracking range & maxPcrError \n", NEXUS_Timebase_e0));
1781        }
1782        /* program the timebase 1: for monitoring the playpump buffer */
1783        NEXUS_Timebase_GetSettings(NEXUS_Timebase_e1, &timebaseSettings);
1784        timebaseSettings.sourceType = NEXUS_TimebaseSourceType_eFreeRun;
1785        timebaseSettings.freeze = true;
1786        timebaseSettings.sourceSettings.pcr.trackRange = NEXUS_TimebaseTrackRange_e122ppm;
1787        rc = NEXUS_Timebase_SetSettings(NEXUS_Timebase_e1, &timebaseSettings);
1788        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1789        BDBG_MSG(("Configured Timebase %d with increased tracking range & maxPcrError \n", NEXUS_Timebase_e1));
1790
1791        /* Update STC Channel Settings */
1792        /* configure the StcChannel to do lipsync with the PCR */
1793        stcChannelSettings.timebase = NEXUS_Timebase_e0;     /* timebase */
1794        stcChannelSettings.mode = NEXUS_StcChannelMode_ePcr; /* Live Mode */
1795        /* offset threshold: uses upper 32 bits (183ticks/msec) of PCR clock */
1796        stcChannelSettings.modeSettings.pcr.offsetThreshold = 8;
1797        /* max pcr error: uses upper 32 bits (183ticks/msec) of PCR clock */
1798        stcChannelSettings.modeSettings.pcr.maxPcrError = 255;
1799        stcChannelSettings.modeSettings.pcr.pidChannel = pcrPidChannel;
1800        /*  PCR Offset "Jitter Adjustment" is not suitable for use with IP channels Channels, so disable it */
1801        stcChannelSettings.modeSettings.pcr.disableJitterAdjustment = true;
1802        /* Disable Auto Timestamp correction for PCR Jitter */
1803        stcChannelSettings.modeSettings.pcr.disableTimestampCorrection = true;
1804        /* We just configured the Timebase, so turn off auto timebase config */
1805        stcChannelSettings.autoConfigTimebase = false;
1806        break;
1807
1808    case B_PlaybackIpClockRecoveryMode_ePull:
1809        /* PVR/Pull mode */ 
1810        if (psi.videoPid) {
1811            stcChannelSettings.timebase = NEXUS_Timebase_e0;     /* timebase */
1812            stcChannelSettings.mode = NEXUS_StcChannelMode_eAuto; /* PVR (Pull) Mode */
1813            stcChannelSettings.modeSettings.Auto.transportType = psi.mpegType;
1814        }
1815        break;
1816    }
1817#if 0
1818    /* check if helpful */
1819    stcChannelSettings.modeSettings.Auto.behavior = NEXUS_StcChannelAutoModeBehavior_eVideoMaster;
1820    stcChannelSettings.modeSettings.Auto.behavior = NEXUS_StcChannelAutoModeBehavior_eAudioMaster;
1821#endif
1822    rc = NEXUS_StcChannel_SetSettings(stcChannel, &stcChannelSettings);
1823    if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1824    /* ----------------------------------------------------------------------------------------------------------------*/
1825
1826
1827    /* ----------------------------------------------------------------------------------------------------------------*/
1828    /* Setup up video decoder */
1829    BDBG_MSG(("Video PID %d, Video Codec %d, Audio PID %d, Audio Codec %d, PCR PID %d, transport type %d, duration %d\n",
1830            psi.videoPid, psi.videoCodec, psi.audioPid, psi.audioCodec, psi.pcrPid, psi.mpegType, psi.duration));
1831    /* Set up decoder Start structures now. We need to know the audio codec to properly set up the audio outputs. */
1832    NEXUS_VideoDecoder_GetDefaultStartSettings(&videoProgram);
1833    if (psi.videoPid) {
1834        videoProgram.codec = psi.videoCodec;
1835        videoProgram.pidChannel = videoPidChannel;
1836        if (psi.audioPid)
1837            videoProgram.stcChannel = stcChannel;
1838        if (extraVideoPidChannel) {
1839            videoProgram.enhancementPidChannel = extraVideoPidChannel;
1840            videoProgram.codec = psi.extraVideoCodec;
1841            BDBG_WRN(("%s: extra video pid channel programmed", __FUNCTION__, extraVideoPidChannel));
1842        }
1843    }
1844
1845    NEXUS_AudioDecoder_GetDefaultStartSettings(&audioProgram);
1846    audioProgram.codec = psi.audioCodec;
1847    audioProgram.pidChannel = audioPidChannel;
1848    if (psi.videoPid) {
1849        audioProgram.stcChannel = stcChannel;
1850    }
1851
1852    #if NEXUS_NUM_AUDIO_DACS
1853    NEXUS_AudioOutput_AddInput(
1854        NEXUS_AudioDac_GetConnector(platformConfig.outputs.audioDacs[0]),
1855        NEXUS_AudioDecoder_GetConnector(pcmDecoder, NEXUS_AudioDecoderConnectorType_eStereo));
1856    #endif
1857    #if NEXUS_NUM_SPDIF_OUTPUTS
1858    if ( audioProgram.codec == NEXUS_AudioCodec_eAc3 )
1859    {
1860        /* Only pass through AC3 */
1861        NEXUS_AudioOutput_AddInput(
1862            NEXUS_SpdifOutput_GetConnector(platformConfig.outputs.spdif[0]),
1863            NEXUS_AudioDecoder_GetConnector(compressedDecoder, NEXUS_AudioDecoderConnectorType_eCompressed));
1864    }
1865    else
1866    {
1867        NEXUS_AudioOutput_AddInput(
1868            NEXUS_SpdifOutput_GetConnector(platformConfig.outputs.spdif[0]),
1869            NEXUS_AudioDecoder_GetConnector(pcmDecoder, NEXUS_AudioDecoderConnectorType_eStereo));
1870    }
1871    #endif
1872    /* configure output rate managers */
1873    switch (playbackIpSettings.ipMode) {
1874    case B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip:
1875        /* Both display & audio outputs are decoupled from input time base & run from a free clock */
1876        #if NEXUS_NUM_AUDIO_DACS
1877        output = NEXUS_AudioDac_GetConnector(platformConfig.outputs.audioDacs[0]);
1878        NEXUS_AudioOutput_GetSettings(output, &audioOutputSettings);
1879        audioOutputSettings.timebase = NEXUS_Timebase_e1;
1880        rc = NEXUS_AudioOutput_SetSettings(output, &audioOutputSettings);
1881        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1882        #endif
1883        #if NEXUS_NUM_SPDIF_OUTPUTS
1884        output = NEXUS_SpdifOutput_GetConnector(platformConfig.outputs.spdif[0]);
1885        NEXUS_AudioOutput_GetSettings(output, &audioOutputSettings);
1886        audioOutputSettings.timebase = NEXUS_Timebase_e1;
1887        rc = NEXUS_AudioOutput_SetSettings(output, &audioOutputSettings);
1888        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1889        #endif
1890#if NEXUS_NUM_HDMI_OUTPUTS
1891        output = NEXUS_HdmiOutput_GetAudioConnector(platformConfig.outputs.hdmi[0] );
1892        NEXUS_AudioOutput_GetSettings(output, &audioOutputSettings);
1893        audioOutputSettings.timebase = NEXUS_Timebase_e1;
1894        rc = NEXUS_AudioOutput_SetSettings(output, &audioOutputSettings);
1895        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1896#endif
1897        /* TODO: Modify timebase of other audio outputs as well (e.g. i2s, etc) */
1898
1899        /* Decouple the Display from input timebase and run it on free running timebase */
1900        NEXUS_Display_GetSettings(display, &displaySettings);
1901        displaySettings.timebase = NEXUS_Timebase_e1;
1902        rc = NEXUS_Display_SetSettings(display, &displaySettings);
1903        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1904        break;
1905    case B_PlaybackIpClockRecoveryMode_ePushWithTtsNoSyncSlip:
1906    case B_PlaybackIpClockRecoveryMode_ePushWithPcrNoSyncSlip:
1907    case B_PlaybackIpClockRecoveryMode_ePull:
1908        break;
1909    }
1910    /* ----------------------------------------------------------------------------------------------------------------*/
1911
1912    /* ----------------------------------------------------------------------------------------------------------------*/
1913    /* Two additional AV decoder seetings are needed for Live IP Mode */
1914    /*  1. Delay the start of decoder as per the network jitter by increasing the PTS Offset */
1915    /*  2. Tell the decoder that it is in the live mode */
1916    if (psi.videoPid) {
1917            NEXUS_VideoDecoder_GetSettings(videoDecoder, &videoDecoderSettings);
1918        if (playbackIpSettings.ipMode == B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip) {
1919            videoDecoderSettings.ptsOffset = IP_NETWORK_JITTER * 45;    /* In 45Khz clock */
1920        }
1921
1922        videoDecoderSettings.sourceChanged.callback = sourceChangeCallback;
1923        videoDecoderSettings.sourceChanged.context = videoDecoder;
1924        videoDecoderSettings.sourceChanged.param = 1;
1925        rc = NEXUS_VideoDecoder_SetSettings(videoDecoder, &videoDecoderSettings);
1926        if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1927        BDBG_MSG(("Video Decoder settings are modified for IP \n"));
1928        if (!psi.audioPid) {
1929            NEXUS_VideoDecoderExtendedSettings pSettings;
1930            NEXUS_VideoDecoder_GetExtendedSettings(videoDecoder, &pSettings);
1931            pSettings.zeroDelayOutputMode = true;
1932            pSettings.ignoreDpbOutputDelaySyntax = true;
1933            rc = NEXUS_VideoDecoder_SetExtendedSettings(videoDecoder, &pSettings);
1934            if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1935            BDBG_WRN(("Video Decoder extended settings are modified Ip Mode"));
1936        }
1937    }
1938
1939    if (psi.audioPid) {
1940        NEXUS_AudioDecoder_GetSettings(pcmDecoder, &audioDecoderSettings);             
1941        if (playbackIpSettings.ipMode == B_PlaybackIpClockRecoveryMode_ePushWithPcrSyncSlip) {
1942            audioDecoderSettings.ptsOffset = IP_NETWORK_JITTER * 45;    /* In 45Khz clock */
1943        }
1944
1945        audioDecoderSettings.sourceChanged.callback = sourceChangeCallback;
1946        audioDecoderSettings.sourceChanged.context = pcmDecoder;
1947        audioDecoderSettings.sourceChanged.param = 0;
1948        rc = NEXUS_AudioDecoder_SetSettings(pcmDecoder, &audioDecoderSettings);
1949        if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1950        BDBG_MSG(("PCM Audio Decoder settings are modified for IP \n"));
1951
1952        NEXUS_AudioDecoder_GetSettings(compressedDecoder, &audioDecoderSettings);
1953        audioDecoderSettings.ptsOffset = IP_NETWORK_JITTER * 45;    /* In 45Khz clock */
1954        rc = NEXUS_AudioDecoder_SetSettings(compressedDecoder, &audioDecoderSettings);
1955        if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
1956        BDBG_MSG(("Compressed Audio Decoder settings are modified for IP \n"));
1957    }
1958    /* ----------------------------------------------------------------------------------------------------------------*/
1959
1960#if NEXUS_HAS_SYNC_CHANNEL
1961    if (!ipCfg.fastChannelChange) {
1962        /* connect sync channel */
1963        NEXUS_SyncChannel_GetSettings(syncChannel, &syncChannelSettings);
1964        syncChannelSettings.videoInput = NEXUS_VideoDecoder_GetConnector(videoDecoder);
1965        if (psi.audioPid) {
1966            syncChannelSettings.audioInput[0] = NEXUS_AudioDecoder_GetConnector(pcmDecoder, NEXUS_AudioDecoderConnectorType_eStereo);
1967#if 0
1968            syncChannelSettings.audioInput[1] = NEXUS_AudioDecoder_GetConnector(compressedDecoder, NEXUS_AudioDecoderConnectorType_eCompressed);
1969#endif
1970        }
1971        NEXUS_SyncChannel_SetSettings(syncChannel, &syncChannelSettings);
1972    }
1973#endif
1974
1975#if 0
1976    /* Needed to comment out starting the compressed decoder, otherwise client based trickmodes for TS content were not working */
1977    /* as this decoder was not getting flushed during trick play transition. Need to look into this at some point */
1978    if (psi.audioPid && audioProgram.codec == NEXUS_AudioCodec_eAc3 )
1979    {
1980        /* Only pass through AC3 */
1981        rc = NEXUS_AudioDecoder_Start(compressedDecoder, &audioProgram);
1982        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__); exit(1);}
1983    }
1984#endif
1985
1986    if (ipCfg.fastChannelChange) {
1987        NEXUS_VideoDecoderPrimerSettings primerSettings;
1988        for (i=0;i<TOTAL_PRIMERS;i++) {
1989            NEXUS_VideoDecoder_GetPrimerSettings(primer[i], &primerSettings);
1990            primerSettings.pastTolerance = 1500; /* amount of time willing to race: for IP, start decode from the previous GOP */
1991            primerSettings.futureTolerance = 0;
1992            rc = NEXUS_VideoDecoder_SetPrimerSettings(primer[i], &primerSettings);
1993
1994            /* now start the primer */
1995            NEXUS_VideoDecoder_StartPrimer(videoDecoder, primer[i], &videoProgram);
1996        }
1997    }
1998
1999    /* Start Playing Media */
2000    if (!playbackIpSettings.useNexusPlaypump) {
2001        BDBG_MSG(("Start Nexus Playback \n"));
2002        rc = NEXUS_Playback_Start(playback, ipSessionSetupStatus.u.http.file, NULL);
2003        if (rc) {
2004            BDBG_ERR(("NEXUS Error (%d) at %d, retrying w/o index..\n", rc, __LINE__));
2005            rc = B_PlaybackIp_SessionStop(playbackIp);
2006            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2007            rc = B_PlaybackIp_SessionClose(playbackIp);
2008            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2009
2010            BDBG_WRN(("Starting IP Applib: w/o index this time..."));
2011            ipSessionOpenSettings.nonBlockingMode = false;
2012            rc = B_PlaybackIp_SessionOpen(playbackIp, &ipSessionOpenSettings, &ipSessionOpenStatus);
2013            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2014            ipSessionSetupSettings.u.http.dontUseIndex = true;
2015            rc = B_PlaybackIp_SessionSetup(playbackIp, &ipSessionSetupSettings, &ipSessionSetupStatus);
2016            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2017
2018            rc = NEXUS_Playback_Start(playback, ipSessionSetupStatus.u.http.file, NULL);
2019            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2020        }
2021        BDBG_MSG(("Nexus Playback is started\n"));
2022    }
2023    else {
2024        /* playpump is used for all Live modes including Http Live Streaming */
2025        rc = NEXUS_Playpump_Start(playpump);
2026        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2027        BDBG_MSG(("Nexus Playpump is started\n"));
2028    }
2029    audioStarted = true;
2030    /* ----------------------------------------------------------------------------------------------------------------*/
2031
2032    /* let IP Applib go ... */
2033    memset(&ipSessionStartSettings, 0, sizeof(ipSessionStartSettings));
2034    if (ipCfg.protocol == B_PlaybackIpProtocol_eHttp) {
2035        ipSessionStartSettings.u.http.preChargeBuffer = false;    /* precharging done via the preChargeNetworkBuffer() call below */
2036    }
2037    else if (ipCfg.protocol == B_PlaybackIpProtocol_eRtsp) {
2038        ipSessionStartSettings.u.rtsp.mediaTransportProtocol = B_PlaybackIpProtocol_eRtp;  /* protocol used to carry actual media */
2039        ipSessionStartSettings.u.rtsp.keepAliveInterval = 10;  /* send rtsp heart beats (keepalive) every 10sec */
2040    }
2041    /* set Nexus handles */
2042    if (playpump)
2043        ipSessionStartSettings.nexusHandles.playpump = playpump;
2044    if (playback)
2045        ipSessionStartSettings.nexusHandles.playback = playback;
2046    if (psi.videoPid) {
2047        ipSessionStartSettings.nexusHandles.videoDecoder = videoDecoder;
2048    }
2049    if (stcChannel) 
2050        ipSessionStartSettings.nexusHandles.stcChannel = stcChannel;
2051    if (psi.audioPid && pcmDecoder) {
2052        ipSessionStartSettings.nexusHandles.primaryAudioDecoder = pcmDecoder;
2053    }
2054#if 0
2055    if (compressedDecoder)
2056        ipSessionStartSettings.nexusHandles.secondaryAudioDecoder = compressedDecoder;
2057#endif
2058    ipSessionStartSettings.nexusHandlesValid = true;
2059    ipSessionStartSettings.mpegType = psi.mpegType;
2060    rc = B_PlaybackIp_SessionStart(playbackIp, &ipSessionStartSettings, &ipSessionStartStatus);
2061    while (rc == B_ERROR_IN_PROGRESS) {
2062        /* app can do some useful work while SessionSetup is in progress and resume when callback sends the completion event */
2063        BDBG_WRN(("Session Start call in progress, sleeping for now..."));
2064        BKNI_Sleep(100);
2065        rc = B_PlaybackIp_SessionStart(playbackIp, &ipSessionStartSettings, &ipSessionStartStatus);
2066    }
2067    if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); goto error;}
2068
2069    if (ipCfg.fastChannelChange && psi.videoPid) {
2070        BDBG_WRN(("Press ENTER to switch programs\n"));
2071        getchar();
2072        BDBG_WRN(("Starting Decoder w/ Primer ...\n"));
2073        rc = NEXUS_VideoDecoder_StartDecodeWithPrimer(videoDecoder, primer[0]);
2074        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); goto errorClose;}
2075        BDBG_MSG(("Video Decoder Primer is Started\n"));
2076    }
2077    else {
2078        /* Start Decoders */
2079        if (psi.videoPid) {
2080            rc = NEXUS_VideoDecoder_Start(videoDecoder, &videoProgram);
2081            if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); goto errorClose;}
2082            BDBG_MSG(("Video Decoder is Started\n"));
2083        }
2084    }
2085
2086    if (psi.audioPid) {
2087        rc = NEXUS_AudioDecoder_Start(pcmDecoder, &audioProgram);
2088        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2089        BDBG_MSG(("Audio Decoder is Started\n"));
2090    }
2091    /* TODO: wait for PreChangeEvent */
2092    /* Now pre-charge n/w buffer if configured */
2093    if (ipCfg.preChargeTime && !ipCfg.initialSeekTime) {
2094        /* do initial pre-charging only if we are not doing any initial seeks */
2095        if (preChargeNetworkBuffer(playbackIp, ipCfg.preChargeTime)) {
2096            BDBG_ERR((" #### Initial pre-charge of Network buffer of %d sec failed\n", ipCfg.preChargeTime));
2097            exit(1);
2098        }
2099        BDBG_WRN((" #### Initial Network pre-charge of %d sec is complete", ipCfg.preChargeTime));
2100        rc = NEXUS_Playback_Play(playback);
2101        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2102    }
2103
2104    /* ----------------------------------------------------------------------------------------------------------------*/
2105
2106
2107    BDBG_WRN(("Nexus & Platform Setup complete"));
2108    if (ipCfg.initialSeekTime) {
2109        /* user wants to skip to specified time in seconds */
2110        if (B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2111            BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); 
2112            exit(1);
2113        }
2114#if 0
2115        BDBG_WRN(("Seeking Playback by %d sec", ipCfg.initialSeekTime));
2116        rc = NEXUS_Playback_Seek(playback, ipCfg.initialSeekTime * 1000);
2117        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2118        BDBG_WRN(("Seeked Playback by %d sec\n", ipCfg.initialSeekTime));
2119
2120        if (preChargeNetworkBuffer(playbackIp, ipCfg.preChargeTime)) {
2121            BDBG_ERR((" #### Initial pre-charge of Network buffer of %d sec failed\n", ipCfg.preChargeTime));
2122            exit(1);
2123        }
2124        BDBG_WRN((" #### initial Seek: Network pre-charge of %d sec is complete", ipCfg.preChargeTime));
2125
2126        rc = NEXUS_Playback_Play(playback);
2127        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2128#else
2129        B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings);
2130        ipTrickModeSettings.seekPositionIsRelative = false;
2131        ipTrickModeSettings.seekBackward = false;
2132        ipTrickModeSettings.seekPosition = ipCfg.initialSeekTime*1000; /* in msec */
2133        if (B_PlaybackIp_Seek(playbackIp, &ipTrickModeSettings)) { 
2134            BDBG_ERR(("ERROR: Failed to seek Ip playback\n"));
2135            goto error;
2136        }
2137#endif
2138        BDBG_WRN(("Initial Seek successful, playback is started at correct time offset"));
2139    }
2140
2141    /* Set stdin to non-blocking */
2142    if (fcntl(0, F_SETFL, fcntl(0, F_GETFL) |O_NONBLOCK) < 0)
2143        BDBG_WRN(("ERROR setting non-blocking mode on STDIN\n"));
2144   
2145    if (psi.videoPid & !psi.audioPid) {
2146        NEXUS_VideoDecoderTrickState videoDecoderTrickSettings;
2147        NEXUS_VideoDecoder_GetTrickState(videoDecoder, &videoDecoderTrickSettings);
2148        videoDecoderTrickSettings.tsmEnabled = false;
2149        if (NEXUS_VideoDecoder_SetTrickState(videoDecoder, &videoDecoderTrickSettings) != NEXUS_SUCCESS) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1); }
2150        BDBG_WRN(("Disabling TSM...."));
2151    }
2152    while (!gEof) {
2153        static int state = 1;
2154        int curBufferDuration; 
2155        static unsigned prevPts = 0;
2156        static int rate = 1;
2157        static unsigned playSpeedIndex;
2158        static bool usingServerBasedTrickModes = false;
2159        /* Sleep for a second before we check any status */
2160        gEof = false;
2161        BKNI_Sleep(1000);
2162
2163        /* Print various status while decoding */
2164        NEXUS_VideoDecoder_GetStatus(videoDecoder, &videoStatus);
2165        rc = NEXUS_Playback_GetStatus(playback, &pbStatus);
2166        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2167        NEXUS_AudioDecoder_GetStatus(pcmDecoder, &audioStatus);
2168        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2169        rc = NEXUS_Playpump_GetStatus(playpump, &ppStatus);
2170        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2171        rc = B_PlaybackIp_GetStatus(playbackIp, &playbackIpStatus);
2172        if (rc) {BDBG_WRN(("NEXUS Error (%d) at %d, returning...\n", rc, __LINE__)); return (-1);}
2173        if (psi.videoPid & psi.audioPid) 
2174            NEXUS_StcChannel_GetStc(videoProgram.stcChannel, &stc);
2175
2176        if (ipCfg.decoderStats) {
2177            BDBG_WRN(("decode %.4dx%.4d, pts %#x, stc %#x (diff %d) fifo size %d, depth %d, fullness %d%%\n",
2178            videoStatus.source.width, videoStatus.source.height, videoStatus.pts, stc, videoStatus.ptsStcDifference, videoStatus.fifoSize, videoStatus.fifoDepth, videoStatus.fifoSize?(videoStatus.fifoDepth*100)/videoStatus.fifoSize:0));
2179            BDBG_WRN(("audio0            pts %#x, stc %#x (diff %d) fifo size %d, depth %d, fullness %d%%\n",
2180            audioStatus.pts, stc, audioStatus.ptsStcDifference, audioStatus.fifoSize, audioStatus.fifoDepth, audioStatus.fifoSize?(audioStatus.fifoDepth*100)/audioStatus.fifoSize:0));
2181#if 0
2182            NEXUS_AudioDecoder_GetStatus(compressedDecoder, &audioStatus);
2183#endif
2184            if ( audioStatus.started ) {
2185                BDBG_WRN(("audio1            pts %#x, stc %#x (diff %d) fifo size %d, depth %d, fullness %d%%\n",
2186                audioStatus.pts, stc, audioStatus.ptsStcDifference, audioStatus.fifoSize, audioStatus.fifoDepth, audioStatus.fifoSize?(audioStatus.fifoDepth*100)/audioStatus.fifoSize:0));
2187            }
2188            BDBG_WRN(("q depth %d, decoded %d, displayed %d, decode errs %d, display errs %d, decode drops %d, display drops %d, display underflow %d, received %d, pts errs %d\n",
2189                    videoStatus.queueDepth, videoStatus.numDecoded, videoStatus.numDisplayed, videoStatus.numDecodeErrors,
2190                    videoStatus.numDisplayErrors, videoStatus.numDecodeDrops, videoStatus.numDisplayDrops, videoStatus.numDisplayUnderflows, videoStatus.numPicturesReceived, videoStatus.ptsErrorCount));
2191
2192            BDBG_WRN(("playback: ip pos %lu, pb pos %lu, fed %lu, first %lu, last %lu, PB buffer depth %d, size %d, fullness %d%%, played bytes %lld\n", 
2193                    playbackIpStatus.position, pbStatus.position, pbStatus.readPosition, pbStatus.first, pbStatus.last, ppStatus.fifoDepth, ppStatus.fifoSize, 
2194                    (ppStatus.fifoDepth*100)/ppStatus.fifoSize, ppStatus.bytesPlayed));
2195        }
2196
2197        if (psi.hlsSessionEnabled && playbackIpStatus.position >= (psi.duration*1000)) {
2198            BDBG_WRN(("%s: Finished playing the stream, setting EOF flag, current position %dsec, total duration %dsec", __FUNCTION__, playbackIpStatus.position/1000, psi.duration));
2199            gEof = true;
2200            break;
2201        }
2202        if (playbackIpStatus.ipState == B_PlaybackIpState_eTrickMode && gEof) {
2203            if (B_PlaybackIp_Play(playbackIp)) {
2204                BDBG_ERR(("ERROR: Failed to pause Ip playback\n"));
2205                goto error;
2206            }
2207            state = 1;
2208            rate = 1;
2209        }
2210        else if (playbackIpStatus.ipState == B_PlaybackIpState_ePaused || playbackIpStatus.ipState == B_PlaybackIpState_eTrickMode)
2211            goto skip_runtime_buffering_check;
2212#define RUNTIME_BUFFERING_CODE
2213#ifdef RUNTIME_BUFFERING_CODE
2214        if (psi.mpegType == NEXUS_TransportType_eMp4) {
2215            curBufferDuration = pbStatus.readPosition - pbStatus.position;
2216            BDBG_MSG(("buffered %d mill-seconds worth of MP4 content\n", curBufferDuration));
2217        }
2218        else if (psi.mpegType == NEXUS_TransportType_eAsf) {
2219            curBufferDuration = (ppStatus.mediaPts - (psi.videoPid?videoStatus.pts:audioStatus.pts))/45;
2220            BDBG_MSG(("buffered %d milli-seconds worth of ASF content\n", curBufferDuration));
2221        }
2222        else {
2223            /* we need to use alternate means to determine the amount of buffering in system since such formats are not processed in sw and thus we dont know the curBufferDepth */
2224            /* instead, we can detect the underflow condition by monitoring the last pts displayed, once it doesn't change, we are definitely underflowing and thus can precharge */
2225            /* by default, set curBufferDuration to a higher number to avoid precharging */
2226            curBufferDuration = 99999; /* set to some large value */
2227            if (prevPts) {
2228                if (prevPts == (psi.videoPid?videoStatus.pts:audioStatus.pts)) {
2229                    /* pts hasn't changed, so we are underflowing, set flag to precharge */
2230                    BDBG_MSG(("pts hasn't changed, so we are underflowing, prev pts, %u, cur pts %u, pre charge time %d\n", prevPts, psi.videoPid?videoStatus.pts:audioStatus.pts, ipCfg.preChargeTime));
2231                    curBufferDuration = 0;
2232                }
2233            }
2234            prevPts = psi.videoPid?videoStatus.pts:audioStatus.pts;
2235            BDBG_MSG(("prev pts, %u, cur pts %u\n", prevPts, psi.videoPid?videoStatus.pts:audioStatus.pts));
2236        }
2237        if (ipCfg.preChargeTime && (curBufferDuration < 200)) {
2238            /* we are precharging & current buffer level is below the low water mark, so start pre-charging */
2239            /* however, sleep quickly to see if underflow is due to EOF. Otherwise, we will Pause Playback too quickly */
2240            /* before we get the EOF callback. Sleep gives Nexus Playback a chance to invoke the eof callback. */
2241            BKNI_Sleep(500);
2242            if (gEof) {
2243                BDBG_WRN(("Underflow is due to EOF, breaking out...\n"));
2244                break;
2245            }
2246            BDBG_WRN(("Underflowing, so pausing the playback until enough buffering is done..."));
2247            if (NEXUS_Playback_Pause(playback)) {
2248                BDBG_WRN(("ERROR: Failed to pause Nexus playback\n"));
2249                break;
2250            }
2251            BDBG_MSG(("Paused Nexus Playback...\n"));
2252
2253            /* Now pre-charge n/w buffer */
2254            if (preChargeNetworkBuffer(playbackIp, ipCfg.preChargeTime)) {
2255                BDBG_ERR((" #### runtime pre-charge of Network buffer of %d sec failed\n", ipCfg.preChargeTime));
2256                break;
2257            }
2258            BDBG_MSG(("Resuming Playback\n"));
2259            if (NEXUS_Playback_Play(playback)) {
2260                BDBG_WRN(("ERROR: Failed to play Nexus playback from pause\n"));
2261                break;
2262            }
2263        }
2264skip_runtime_buffering_check:
2265#endif
2266
2267        /* Exit loop if character is entered */
2268        memset(buf, 0, sizeof(buf));
2269        numbytes = read(0,buf,sizeof(buf));
2270        BDBG_MSG(("User interrupted loop. STDIN received data, numbytes %d, errno %d\n", numbytes, errno));
2271        if (numbytes > 0) {
2272            if (buf[0] == 'p' && state == 1) {
2273                state = 0;
2274                if (B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2275                    BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); 
2276                    exit(1);
2277                }
2278                ipTrickModeSettings.pauseMethod = B_PlaybackIpPauseMethod_UseConnectionStalling;
2279                ipTrickModeSettings.pauseMethod = B_PlaybackIpPauseMethod_UseDisconnectAndSeek;
2280                BDBG_WRN(("Pausing Playback using method %d", ipTrickModeSettings.pauseMethod));
2281                if (B_PlaybackIp_Pause(playbackIp, &ipTrickModeSettings)) {
2282                    BDBG_ERR(("ERROR: Failed to pause Ip playback\n"));
2283                    goto error;
2284                }
2285            }
2286            else if (buf[0] == 'p' && state == 0) {
2287                BDBG_WRN(("Resuming Playback"));
2288                state = 1;
2289                rate = 1;
2290                if (B_PlaybackIp_Play(playbackIp)) {
2291                    BDBG_ERR(("ERROR: Failed to pause Ip playback\n"));
2292                    goto error;
2293                }
2294                BDBG_WRN(("After Resuming Playback"));
2295            }
2296            else if (strncmp(buf, "fs", 2) == 0 || strncmp(buf, "rs", 2) == 0 ) {
2297                int dir = (strncmp(buf, "fs", 2) == 0) ? 1 : -1;
2298                int rate;
2299                buf[5] = buf[6] = '\0';
2300                rate = atoi(&buf[2]);
2301                if (rate == 0 || rate > NEXUS_NORMAL_PLAY_SPEED)
2302                    rate = NEXUS_NORMAL_PLAY_SPEED;
2303                state = 0;  /* goto to play when when p is entered */
2304                BDBG_WRN(("set the trick play slow %s command", dir == 1?"fwd": "rwd"));
2305                if (B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2306                    BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); 
2307                    exit(1);
2308                }
2309                ipTrickModeSettings.absoluteRateDefined = true;
2310                if (dir > 0)
2311                    ipTrickModeSettings.absoluteRate = rate;
2312                else
2313                    ipTrickModeSettings.absoluteRate = -rate;
2314                if (B_PlaybackIp_TrickMode(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2315                    BDBG_WRN(("Failed to set the trick play speed %d, index %d\n", psi.playSpeed[playSpeedIndex], playSpeedIndex));
2316                    break;
2317                }
2318                BDBG_WRN(("Successfully set the trick play slow %s command", dir == 1?"fwd": "rwd"));
2319            }
2320            else if (buf[0] == 's') {
2321                int seekTime = 0;
2322                buf[6] = '\0';
2323                if (B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2324                    BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); 
2325                    exit(1);
2326                }
2327                if (buf[1] == 'r') {
2328                    /* seek relative */
2329                    seekTime = atoi(&buf[2]);
2330                    ipTrickModeSettings.seekPositionIsRelative = true;
2331                }
2332                else {
2333                    seekTime = atoi(&buf[1]);
2334                    ipTrickModeSettings.seekPositionIsRelative = false;
2335                }
2336
2337                if (seekTime < 0) {
2338                    ipTrickModeSettings.seekPositionIsRelative = true;
2339                    ipTrickModeSettings.seekBackward = true;
2340                    seekTime = ~seekTime + 1;
2341                }
2342                else
2343                    ipTrickModeSettings.seekBackward = false;
2344                /* user wants to skip to specified time in seconds */
2345                ipTrickModeSettings.seekPosition = seekTime*1000; /* in msec */
2346                BDBG_WRN(("IP Playback seeking to %d sec ", seekTime));
2347                if (B_PlaybackIp_Seek(playbackIp, &ipTrickModeSettings)) { 
2348                    BDBG_ERR(("ERROR: Failed to seek Ip playback\n"));
2349                    goto error;
2350                }
2351                state = 1;
2352                BDBG_WRN(("IP Playback is started at %d time pos %u", seekTime, ipTrickModeSettings.seekPosition));
2353            }
2354            else if (buf[0] == 'j') {
2355                /* jump forward by a fixed time (defaults to 5 sec) */
2356                int seekTime = 0;
2357                if (B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2358                    BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); 
2359                    exit(1);
2360                }
2361                /* seek relative */
2362                seekTime = ipCfg.secondsToJump;
2363                ipTrickModeSettings.seekPositionIsRelative = true;
2364                if (seekTime < 0) {
2365                    ipTrickModeSettings.seekBackward = true;
2366                    seekTime = ~seekTime + 1;
2367                }
2368                else
2369                    ipTrickModeSettings.seekBackward = false;
2370                /* user wants to skip to specified time in seconds */
2371                ipTrickModeSettings.seekPosition = seekTime*1000; /* in msec */
2372                BDBG_WRN(("IP Playback jumping to %d sec ", seekTime));
2373                if (B_PlaybackIp_Seek(playbackIp, &ipTrickModeSettings)) { 
2374                    BDBG_ERR(("ERROR: Failed to seek Ip playback\n"));
2375                    goto error;
2376                }
2377                state = 1;
2378                BDBG_WRN(("IP Playback is started at %d time pos %u", seekTime, ipTrickModeSettings.seekPosition));
2379            }
2380            else if (strncmp(buf, "ff", 2) == 0 || strncmp(buf, "fr", 2) == 0 ) {
2381                int dir = (strncmp(buf, "ff", 2) == 0) ? 1 : -1;
2382                state = 0;  /* goto to play when when p is entered */
2383                if (B_PlaybackIp_GetTrickModeSettings(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2384                    BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); 
2385                    exit(1);
2386                }
2387                if (!ipCfg.serverBasedTrickModes) {
2388                    /* client side trickmodes */
2389                    if (dir > 0)
2390                        rate++;
2391                    else {
2392                        if (rate == 1)
2393                            rate = -1;
2394                        else
2395                            rate--;
2396                    }
2397                    ipTrickModeSettings.method = B_PlaybackIpTrickModesMethod_UseByteRange;
2398                    ipTrickModeSettings.rate = rate;
2399#ifdef USE_ABSOLUTE_RATE
2400                    if (dir > 0) {
2401                        ipTrickModeSettings.absoluteRateDefined = true;
2402                        ipTrickModeSettings.absoluteRate = NEXUS_NORMAL_PLAY_SPEED/2;
2403                    } 
2404                    else {
2405                        ipTrickModeSettings.absoluteRateDefined = true;
2406                        ipTrickModeSettings.absoluteRate = -NEXUS_NORMAL_PLAY_SPEED/2;
2407                    } 
2408#endif
2409                    ipTrickModeSettings.pauseMethod = B_PlaybackIpPauseMethod_UseDisconnectAndSeek;
2410                    if (B_PlaybackIp_TrickMode(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2411                            BDBG_WRN(("Failed to set the trick play rate %d for client side trickmodes\n", rate));
2412                            break;
2413                    }
2414                    BDBG_WRN(("Successfuly set the trick play rate %d for client side trickmodes", rate));
2415                    usingServerBasedTrickModes = false;
2416                }
2417                else {
2418                    /* server side trickmodes */
2419                    BDBG_WRN(("trick play rate %d, index %d, totol entries %d", rate, playSpeedIndex, psi.numPlaySpeedEntries));
2420                    if (psi.numPlaySpeedEntries > 1) {
2421                        unsigned i;
2422                        /* server has provided various supported speeds during trick mode */
2423                        ipTrickModeSettings.method = B_PlaybackIpTrickModesMethod_UsePlaySpeed;
2424                        ipTrickModeSettings.pauseMethod = B_PlaybackIpPauseMethod_UseDisconnectAndSeek;
2425                        /* now pick the correct speed from the playSpeed Arrary */
2426                        if (rate == 1 && dir> 0) {
2427                            /* we are now switching from normal to FFWD trick play, find the 1st positive speed */
2428                            for (i=0; i< psi.numPlaySpeedEntries; i++) {
2429                                if (psi.playSpeed[i] > 0) {
2430                                    /* 1st positive speed */
2431                                    playSpeedIndex = i;
2432                                    break;
2433                                }
2434                            }
2435                        }
2436                        else if (rate == 1 && dir < 0) {
2437                            /* we are now switching from normal to FREW trick play, find the 1st -ve speed */
2438                            for (i=0; i< psi.numPlaySpeedEntries; i++) {
2439                                if (psi.playSpeed[i] > 0) {
2440                                    /* 1st positive speed */
2441                                    playSpeedIndex = i-1;
2442                                    break;
2443                                }
2444                            }
2445                        }
2446                        else {
2447                            /* we are already in the fwd trick play state, update the index */
2448                            if (dir>0)
2449                                playSpeedIndex++;
2450                            else
2451                                playSpeedIndex--;
2452                        }
2453                        if (playSpeedIndex >= psi.numPlaySpeedEntries) {
2454                            playSpeedIndex = psi.numPlaySpeedEntries - 1;
2455                        }
2456                        ipTrickModeSettings.rate = psi.playSpeed[playSpeedIndex];
2457                        if (ipTrickModeSettings.rate >= psi.httpMinIFrameSpeed || dir < 0)
2458                            ipTrickModeSettings.frameRepeat = psi.httpFrameRepeat;
2459                        else
2460                            ipTrickModeSettings.frameRepeat = 1;
2461                        if (B_PlaybackIp_TrickMode(playbackIp, &ipTrickModeSettings) != B_ERROR_SUCCESS) {
2462                            BDBG_WRN(("Failed to set the trick play speed %d, index %d\n", psi.playSpeed[playSpeedIndex], playSpeedIndex));
2463                            break;
2464                        }
2465                        BDBG_WRN(("Successfully set the trick play speed %d, index %d, slow motion %d", psi.playSpeed[playSpeedIndex], playSpeedIndex, ipTrickModeSettings.frameRepeat));
2466                        usingServerBasedTrickModes = true;
2467                        rate++;
2468                    }
2469                }
2470            }
2471            else if (strncmp(buf, "q", 1) == 0) {
2472                BDBG_WRN(("user entered %s, breaking from loop", buf));
2473                break;
2474            }
2475            else if (strncmp(buf, "h", 1) == 0 || strncmp(buf, "?", 1) == 0) {
2476                BDBG_WRN(("runtime options are--->\n"));
2477                printf("\ts[-+]<num>: seek to this absolute position in sec. e.g. s30 to seek to 30sec in movie\n");
2478                printf("\tsr[-+]<num>: seek relative in backward or forward direction by sec. e.g. sr-30 to seek to 30sec backwards from current point\n");
2479                printf("\tj<: jump forward or backward by fixed time (defaults to 5sec, modified via -j startup option.\n");
2480                printf("\tp: toggle between pause/play playback\n");
2481                printf("\tff: fast forward to next +ve speed \n");
2482                printf("\tfr: fast rewind to previous -ve speed\n");
2483            }
2484            else {
2485                BDBG_WRN(("Continuing loop: user entered %s", buf));
2486            }
2487        } /* else assume EAGAIN */
2488
2489        if (ipCfg.runUnitTests) {
2490            runPlaybackIpUnitTests(&psi, playbackIp);
2491            if (!ipCfg.loop) {
2492                BDBG_WRN(("Breaking main loop"));
2493                break;
2494            }
2495        }
2496    }
2497
2498error:
2499    if (playbackIp)
2500        B_PlaybackIp_SessionStop(playbackIp);
2501    #if NEXUS_NUM_AUDIO_DACS
2502    NEXUS_AudioOutput_RemoveAllInputs(NEXUS_AudioDac_GetConnector(platformConfig.outputs.audioDacs[0]));
2503    #endif
2504    #if NEXUS_NUM_SPDIF_OUTPUTS
2505    NEXUS_AudioOutput_RemoveAllInputs(NEXUS_SpdifOutput_GetConnector(platformConfig.outputs.spdif[0]));
2506    #endif
2507    NEXUS_AudioInput_Shutdown(NEXUS_AudioDecoder_GetConnector(pcmDecoder, NEXUS_AudioDecoderConnectorType_eStereo));
2508    NEXUS_AudioInput_Shutdown(NEXUS_AudioDecoder_GetConnector(compressedDecoder, NEXUS_AudioDecoderConnectorType_eCompressed));
2509    if (audioPidChannel) NEXUS_AudioDecoder_Stop(pcmDecoder);
2510    NEXUS_VideoDecoder_Stop(videoDecoder);
2511
2512    /* Do cleanup necessary for changing channels */
2513    if (!playbackIpSettings.useNexusPlaypump) {
2514        BDBG_WRN(("Stopping Nexus Playback module"));
2515        if(playback)
2516        {
2517            NEXUS_Playback_CloseAllPidChannels(playback);
2518            NEXUS_Playback_Stop(playback);
2519        }
2520    }
2521    else {
2522        BDBG_WRN(("Stopping Nexus Playpump module"));
2523        NEXUS_Playpump_Stop(playpump);
2524        /* NEXUS_Playpump_CloseAllPidChannels(playpump);*/
2525        NEXUS_Playpump_ClosePidChannel(playpump, videoPidChannel);
2526        if (audioPidChannel) NEXUS_Playpump_ClosePidChannel(playpump, audioPidChannel);
2527        if (pcrPidChannel != videoPidChannel)
2528            NEXUS_Playpump_ClosePidChannel(playpump, pcrPidChannel);
2529    }
2530
2531errorClose:
2532#if NEXUS_HAS_SYNC_CHANNEL
2533    if (!ipCfg.fastChannelChange) {
2534        /* disconnect sync channel */
2535        NEXUS_SyncChannel_GetSettings(syncChannel, &syncChannelSettings);
2536        syncChannelSettings.videoInput = NULL;
2537        syncChannelSettings.audioInput[0] = NULL;
2538        syncChannelSettings.audioInput[1] = NULL;
2539        NEXUS_SyncChannel_SetSettings(syncChannel, &syncChannelSettings);
2540        NEXUS_SyncChannel_Destroy(syncChannel);
2541    }
2542#endif
2543
2544    /* Close Socket related resources */
2545    if (playbackIp != NULL) {
2546        /* coverity[freed_arg=FALSE] */
2547        /* coverity[double_free=FALSE] */
2548        rc = B_PlaybackIp_SessionClose(playbackIp);
2549        if (rc) {BDBG_ERR(("NEXUS Error (%d) at %d, Exiting...\n", rc, __LINE__)); exit(1);}
2550    }
2551
2552    if (ipCfg.playMultipleStreams) {
2553        char *prevUrl = "/";
2554        static bool playAudio = 1;
2555
2556        if (playAudio) {
2557            prevUrl = ipCfg.url;
2558            ipCfg.url = "/audio/mpeg/test5.mp3";
2559            ipCfg.url = "/test5.mp3";
2560            playAudio = false;
2561        }
2562        else {
2563            /* break for now */
2564            goto done;
2565        }
2566        BDBG_WRN((" ############## playing another stream ################ "));
2567        goto newSession;
2568    }
2569done:
2570#ifdef B_HAS_DTCP_IP
2571    /* close the per session handle */
2572    if (ipCfg.security == B_PlaybackIpSecurityProtocol_DtcpIp) {
2573        if (DtcpAppLib_CloseAke(dtcpCtx, AkeHandle) != BERR_SUCCESS) {
2574            BDBG_WRN(("%s: failed to close the DTCP AKE session", __FUNCTION__));
2575        }
2576        B_PlaybackIp_DtcpIpUnInit(dtcpCtx);
2577#ifdef B_DTCP_IP_HW_DECRYPTION
2578        DtcpCleanupHwSecurityParams();
2579#endif
2580    }
2581#endif
2582
2583#ifdef B_HAS_SSL
2584    if (ipCfg.security == B_PlaybackIpSecurityProtocol_Ssl){
2585        B_PlaybackIp_SslUnInit(ssl_ctx);
2586    }
2587#endif
2588
2589    NEXUS_AudioDecoder_Close(pcmDecoder);
2590    NEXUS_AudioDecoder_Close(compressedDecoder);
2591    NEXUS_VideoWindow_RemoveAllInputs(window);
2592    NEXUS_VideoInput_Shutdown(NEXUS_VideoDecoder_GetConnector(videoDecoder));
2593    NEXUS_VideoWindow_Close(window);
2594    NEXUS_Display_Close(display);
2595    NEXUS_VideoDecoder_Close(videoDecoder);
2596    NEXUS_StcChannel_Close(stcChannel);
2597    /* Do cleanup necessary for quitting application */
2598    NEXUS_Playback_Destroy(playback);
2599    NEXUS_Playpump_Close(playpump);
2600    B_PlaybackIp_Close(playbackIp);
2601    if (waitEvent) 
2602        BKNI_DestroyEvent(waitEvent);
2603    /* For debugging any memory leaks, use this */
2604    if (ipCfg.decoderStats)
2605        BKNI_Uninit();
2606
2607    return 0;
2608}
Note: See TracBrowser for help on using the repository browser.