| 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 | |
|---|
| 288 | BDBG_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 */ |
|---|
| 297 | NEXUS_AudioDecoderStartSettings audioProgram; |
|---|
| 298 | NEXUS_AudioDecoderHandle pcmDecoder = NULL, compressedDecoder = NULL; |
|---|
| 299 | |
|---|
| 300 | bool audioStarted = false; |
|---|
| 301 | |
|---|
| 302 | typedef 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 | |
|---|
| 326 | int feedToPlayback = 0; |
|---|
| 327 | |
|---|
| 328 | void 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 | |
|---|
| 355 | static 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 | |
|---|
| 379 | static 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: |
|---|
| 463 | usage: |
|---|
| 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 | |
|---|
| 490 | ExampleIpCfg ipCfg; |
|---|
| 491 | int 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 | |
|---|
| 505 | error: |
|---|
| 506 | return 1; |
|---|
| 507 | } |
|---|
| 508 | |
|---|
| 509 | void 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 |
|---|
| 524 | static 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 | |
|---|
| 546 | static 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 | } |
|---|
| 570 | static 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 | |
|---|
| 610 | bool gEof = false; |
|---|
| 611 | static 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 | |
|---|
| 619 | static 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 */ |
|---|
| 628 | int 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 |
|---|
| 706 | B_PlaybackIpEventIds gEventId = B_PlaybackIpEvent_eMax; |
|---|
| 707 | BKNI_EventHandle waitEvent = NULL; |
|---|
| 708 | void 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 | |
|---|
| 725 | void |
|---|
| 726 | runPlaybackIpUnitTests(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 | |
|---|
| 825 | out: |
|---|
| 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 */ |
|---|
| 833 | static bool |
|---|
| 834 | useNexusPlaypumpForIpPlayback( |
|---|
| 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 */ |
|---|
| 859 | static bool |
|---|
| 860 | useLiveModeForIpPlayback( |
|---|
| 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 | |
|---|
| 936 | static 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 | |
|---|
| 942 | static NEXUS_PlatformSettings platformSettings; |
|---|
| 943 | int 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 | |
|---|
| 1275 | newSession: |
|---|
| 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 | } |
|---|
| 1495 | skipTrackInfo: |
|---|
| 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 | } |
|---|
| 2264 | skip_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 | |
|---|
| 2498 | error: |
|---|
| 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 | |
|---|
| 2531 | errorClose: |
|---|
| 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 | } |
|---|
| 2569 | done: |
|---|
| 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 | } |
|---|