Coder Social home page Coder Social logo

channel-engine's People

Contributors

birme avatar craigmc-ottera avatar dependabot[bot] avatar nfrederiksen avatar oscnord avatar saelmala avatar sgtfishtank avatar sinewave440hz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

channel-engine's Issues

Issues with playing live content in Safari

When using consuo.tv as a live source (or another local instance of channel engine) the Safari web player fetches the first couple of live segments and manifests and then stops downloading new segments. This however works as expected in Chrome with the Eyevinn web player without any issues.

When using https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8 as a source for live content everything works as expected in both Safari and in Chromium based browsers.

Can't make it work

Hello,
I'm struggling to make channel-engine work, but with no luck, can someone point to me what I'm doing wrong, I followed the start guide:https://vod2live.docs.eyevinn.technology/, and think the steps are not complex, but this just does not work, Thank you!
2022-12-07T17:22:36.855Z engine-state-store Using MEMORY for non-shared state store (session, cacheTTL=1000)
2022-12-07T17:22:36.858Z engine-state-store Using MEMORY for non-shared state store (playhead, cacheTTL=1000)
2022-12-07T17:22:36.859Z engine-state-store Using MEMORY for non-shared state store (sessionLive, cacheTTL=1000)
2022-12-07T17:22:36.875Z engine-server Starting engine
2022-12-07T17:22:36.876Z engine-server Do we have any new channels?
2022-12-07T17:22:36.877Z engine-server Adding channel with ID myfirstchannel
2022-12-07T17:22:36.886Z engine-server Adding channel with ID myfirstchannel
(node:22827) [DEP0111] DeprecationWarning: Access to process.binding('http_parser') is deprecated.
(Use node --trace-deprecation ... to show where the warning was created)
2022-12-07T17:22:36.899Z engine-server restify listening at http://[::]:8080
2022-12-07T17:22:36.905Z engine-session-live [myfirstchannel]: SessionLive-Playhead consumer started
2022-12-07T17:22:36.909Z engine-session [myfirstchannel]: Playhead consumer started:
2022-12-07T17:22:36.909Z engine-session [myfirstchannel]: diffThreshold=1000
2022-12-07T17:22:36.909Z engine-session [myfirstchannel]: maxTickInterval=10000
2022-12-07T17:22:36.909Z engine-session [myfirstchannel]: averageSegmentDuration=3000
2022-12-07T17:22:36.922Z engine-session [myfirstchannel]: state=VOD_INIT
2022-12-07T17:22:36.923Z engine-session [myfirstchannel]: got first VOD uri=https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8:0
2022-12-07T17:22:37.498Z engine-session [myfirstchannel]: first VOD loaded
2022-12-07T17:22:37.498Z engine-session [myfirstchannel]: 0,3.75,-3.75,0,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,3
.75,-3.75,0,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,3.75,-3.75,0,0,0,0,0,0,-4.75
2022-12-07T17:22:37.499Z engine-session [myfirstchannel]: 0,11.25,18.75,26.25,33.75,41.25,48.75,56.25,63.75,75,82.5,90,97.5,105,112.5,120,131.25,138.75,146.25,153.75,161.25,168.75,176.25,183.75,195,202.5,210,217.5,225,232.5,240,251.25,25
8.75,266.25,273.75,281.25,288.75,296.25,303.75,315,322.5,330,337.5,345,352.5,360,371.25,378.75,386.25,393.75,401.25,408.75,416.25,423.75,435,442.5,450,457.5,465,472.5,480,491.25,498.75,506.25,513.75,521.25,528.75,536.25,543.75,555,562.5,
570,577.5,585,592.5,600,611.25,618.75,626.25,633.75,641.25,648.75,656.25,663.75,666.5
2022-12-07T17:22:37.506Z engine-session [myfirstchannel]: INCREMENT (mseq=1) vodMediaSeq=(1_1 of 85)
2022-12-07T17:22:37.506Z engine-session [myfirstchannel]: current[1]_prev[null]
2022-12-07T17:22:37.506Z engine-session [myfirstchannel]: current-offset[0]_prev-offset[null]
2022-12-07T17:22:37.509Z engine-session [myfirstchannel]: Current delta time (1): 3.75
2022-12-07T17:22:37.510Z engine-session [myfirstchannel]: Delta time is != 0 need will adjust 3.75sec to tick interval. tick=6.1530000000000005
2022-12-07T17:22:37.510Z engine-session [myfirstchannel]: Current playhead position (1): 11.25
2022-12-07T17:22:37.511Z engine-session [myfirstchannel]: 11:11250:+11239ms
2022-12-07T17:22:37.511Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 10.239s
2022-12-07T17:22:37.511Z engine-session [myfirstchannel]: Requested tickInterval=16.392000000000003s (max=10s, diffThreshold=1000msec)
2022-12-07T17:22:37.511Z engine-session [myfirstchannel]: (2022-12-07T17:22:37.511Z) 0.597sec in increment. Next tick in 10 seconds
2022-12-07T17:22:39.902Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:22:39.906Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:22:39.906Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:22:41.913Z engine-server MONITOR: (2022-12-07T17:22:41.913Z) [myfirstchannel]: playhead: running
2022-12-07T17:22:41.913Z engine-server MONITOR: (2022-12-07T17:22:41.913Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:22:42.905Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2997ms
2022-12-07T17:22:42.906Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:22:42.906Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:22:45.905Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:22:45.906Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:22:45.906Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:22:46.910Z engine-server MONITOR: (2022-12-07T17:22:46.910Z) [myfirstchannel]: playhead: running
2022-12-07T17:22:46.911Z engine-server MONITOR: (2022-12-07T17:22:46.911Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:22:47.465Z engine-session [myfirstchannel]: state=VOD_PLAYING (1_1, 85)
2022-12-07T17:22:47.468Z engine-session [myfirstchannel]: INCREMENT (mseq=2) vodMediaSeq=(2_2 of 85)
2022-12-07T17:22:47.470Z engine-session [myfirstchannel]: Current delta time (2): -3.75
2022-12-07T17:22:47.470Z engine-session [myfirstchannel]: Delta time is != 0 need will adjust -3.75sec to tick interval. tick=-0.754
2022-12-07T17:22:47.470Z engine-session [myfirstchannel]: Current playhead position (2): 18.75
2022-12-07T17:22:47.470Z engine-session [myfirstchannel]: 9970:18750:+8780ms
2022-12-07T17:22:47.471Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 7.779999999999999s
2022-12-07T17:22:47.471Z engine-session [myfirstchannel]: Requested tickInterval=7.026s (max=10s, diffThreshold=1000msec)
2022-12-07T17:22:47.471Z engine-session [myfirstchannel]: (2022-12-07T17:22:47.471Z) 0.004sec in increment. Next tick in 7.026 seconds
2022-12-07T17:22:48.905Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:22:48.905Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:22:48.906Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:22:51.905Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:22:51.905Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:22:51.906Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:22:51.910Z engine-server MONITOR: (2022-12-07T17:22:51.910Z) [myfirstchannel]: playhead: running
2022-12-07T17:22:51.910Z engine-server MONITOR: (2022-12-07T17:22:51.910Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:22:54.450Z engine-session [myfirstchannel]: state=VOD_PLAYING (2_2, 85)
2022-12-07T17:22:54.453Z engine-session [myfirstchannel]: INCREMENT (mseq=3) vodMediaSeq=(3_3 of 85)
2022-12-07T17:22:54.455Z engine-session [myfirstchannel]: Current delta time (3): 0
2022-12-07T17:22:54.456Z engine-session [myfirstchannel]: Current playhead position (3): 26.25
2022-12-07T17:22:54.456Z engine-session [myfirstchannel]: 16956:26250:+9294ms
2022-12-07T17:22:54.456Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 8.294s
2022-12-07T17:22:54.456Z engine-session [myfirstchannel]: Requested tickInterval=11.289000000000001s (max=10s, diffThreshold=1000msec)
2022-12-07T17:22:54.456Z engine-session [myfirstchannel]: (2022-12-07T17:22:54.456Z) 0.005sec in increment. Next tick in 10 seconds
2022-12-07T17:22:54.906Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:22:54.906Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:22:54.906Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:22:56.913Z engine-server MONITOR: (2022-12-07T17:22:56.913Z) [myfirstchannel]: playhead: running
2022-12-07T17:22:56.913Z engine-server MONITOR: (2022-12-07T17:22:56.913Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:22:57.908Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:22:57.908Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:22:57.908Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:00.908Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:00.909Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:00.909Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:01.914Z engine-server MONITOR: (2022-12-07T17:23:01.913Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:01.914Z engine-server MONITOR: (2022-12-07T17:23:01.914Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:03.909Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:03.910Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:03.910Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:04.409Z engine-session [myfirstchannel]: state=VOD_PLAYING (3_3, 85)
2022-12-07T17:23:04.413Z engine-session [myfirstchannel]: INCREMENT (mseq=4) vodMediaSeq=(4_4 of 85)
2022-12-07T17:23:04.414Z engine-session [myfirstchannel]: Current delta time (4): 0
2022-12-07T17:23:04.415Z engine-session [myfirstchannel]: Current playhead position (4): 33.75
2022-12-07T17:23:04.415Z engine-session [myfirstchannel]: 26915:33750:+6835ms
2022-12-07T17:23:04.415Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 5.835s
2022-12-07T17:23:04.416Z engine-session [myfirstchannel]: Requested tickInterval=8.83s (max=10s, diffThreshold=1000msec)
2022-12-07T17:23:04.416Z engine-session [myfirstchannel]: (2022-12-07T17:23:04.416Z) 0.005sec in increment. Next tick in 8.83 seconds
2022-12-07T17:23:06.912Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:23:06.913Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:06.913Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:06.916Z engine-server MONITOR: (2022-12-07T17:23:06.916Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:06.916Z engine-server MONITOR: (2022-12-07T17:23:06.916Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:09.913Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:09.913Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:09.913Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:11.918Z engine-server MONITOR: (2022-12-07T17:23:11.918Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:11.918Z engine-server MONITOR: (2022-12-07T17:23:11.918Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:12.914Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:23:12.914Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:12.914Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:13.200Z engine-session [myfirstchannel]: state=VOD_PLAYING (4_4, 85)
2022-12-07T17:23:13.203Z engine-session [myfirstchannel]: INCREMENT (mseq=5) vodMediaSeq=(5_5 of 85)
2022-12-07T17:23:13.205Z engine-session [myfirstchannel]: Current delta time (5): 0
2022-12-07T17:23:13.205Z engine-session [myfirstchannel]: Current playhead position (5): 41.25
2022-12-07T17:23:13.205Z engine-session [myfirstchannel]: 35705:41250:+5545ms
2022-12-07T17:23:13.206Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 4.545s
2022-12-07T17:23:13.206Z engine-session [myfirstchannel]: Requested tickInterval=7.539s (max=10s, diffThreshold=1000msec)
2022-12-07T17:23:13.206Z engine-session [myfirstchannel]: (2022-12-07T17:23:13.206Z) 0.006sec in increment. Next tick in 7.539 seconds
2022-12-07T17:23:15.914Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:15.915Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:15.915Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:16.920Z engine-server MONITOR: (2022-12-07T17:23:16.920Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:16.920Z engine-server MONITOR: (2022-12-07T17:23:16.920Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:18.915Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:18.915Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:18.915Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:20.699Z engine-session [myfirstchannel]: state=VOD_PLAYING (5_5, 85)
2022-12-07T17:23:20.701Z engine-session [myfirstchannel]: INCREMENT (mseq=6) vodMediaSeq=(6_6 of 85)
2022-12-07T17:23:20.703Z engine-session [myfirstchannel]: Current delta time (6): 0
2022-12-07T17:23:20.704Z engine-session [myfirstchannel]: Current playhead position (6): 48.75
2022-12-07T17:23:20.704Z engine-session [myfirstchannel]: 43204:48750:+5546ms
2022-12-07T17:23:20.704Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 4.546s
2022-12-07T17:23:20.704Z engine-session [myfirstchannel]: Requested tickInterval=7.541s (max=10s, diffThreshold=1000msec)
2022-12-07T17:23:20.704Z engine-session [myfirstchannel]: (2022-12-07T17:23:20.704Z) 0.005sec in increment. Next tick in 7.541 seconds
2022-12-07T17:23:21.917Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:23:21.917Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:21.917Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:21.920Z engine-server MONITOR: (2022-12-07T17:23:21.920Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:21.920Z engine-server MONITOR: (2022-12-07T17:23:21.920Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:24.919Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:23:24.919Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:24.919Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:26.922Z engine-server MONITOR: (2022-12-07T17:23:26.922Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:26.922Z engine-server MONITOR: (2022-12-07T17:23:26.922Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:27.921Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:23:27.921Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:27.921Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:28.200Z engine-session [myfirstchannel]: state=VOD_PLAYING (6_6, 85)
2022-12-07T17:23:28.202Z engine-session [myfirstchannel]: INCREMENT (mseq=7) vodMediaSeq=(7_7 of 85)
2022-12-07T17:23:28.204Z engine-session [myfirstchannel]: Current delta time (7): 0
2022-12-07T17:23:28.205Z engine-session [myfirstchannel]: Current playhead position (7): 56.25
2022-12-07T17:23:28.205Z engine-session [myfirstchannel]: 50705:56250:+5545ms
2022-12-07T17:23:28.205Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 4.545s
2022-12-07T17:23:28.205Z engine-session [myfirstchannel]: Requested tickInterval=7.538s (max=10s, diffThreshold=1000msec)
2022-12-07T17:23:28.205Z engine-session [myfirstchannel]: (2022-12-07T17:23:28.205Z) 0.007sec in increment. Next tick in 7.538 seconds
2022-12-07T17:23:30.921Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:30.922Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:30.922Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:31.923Z engine-server MONITOR: (2022-12-07T17:23:31.923Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:31.923Z engine-server MONITOR: (2022-12-07T17:23:31.923Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:33.923Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 3000ms
2022-12-07T17:23:33.923Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:33.923Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:35.698Z engine-session [myfirstchannel]: state=VOD_PLAYING (7_7, 85)
2022-12-07T17:23:35.700Z engine-session [myfirstchannel]: INCREMENT (mseq=8) vodMediaSeq=(8_8 of 85)
2022-12-07T17:23:35.702Z engine-session [myfirstchannel]: Current delta time (8): 0
2022-12-07T17:23:35.702Z engine-session [myfirstchannel]: Current playhead position (8): 63.75
2022-12-07T17:23:35.702Z engine-session [myfirstchannel]: 58202:63750:+5548ms
2022-12-07T17:23:35.703Z engine-session [myfirstchannel]: Playhead stepping msequences too early. Need to wait longer. adding 4.548s
2022-12-07T17:23:35.703Z engine-session [myfirstchannel]: Requested tickInterval=7.543s (max=10s, diffThreshold=1000msec)
2022-12-07T17:23:35.703Z engine-session [myfirstchannel]: (2022-12-07T17:23:35.703Z) 0.005sec in increment. Next tick in 7.543 seconds
2022-12-07T17:23:36.873Z engine-server Do we have any new channels?
2022-12-07T17:23:36.874Z engine-server Have any channels been removed?
2022-12-07T17:23:36.923Z engine-server MONITOR: (2022-12-07T17:23:36.923Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:36.924Z engine-server MONITOR: (2022-12-07T17:23:36.924Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:36.924Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:36.924Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:36.925Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:39.924Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:39.925Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available
2022-12-07T17:23:39.925Z engine-server [myfirstchannel]: streamSwitcher returned switchstatus=false
2022-12-07T17:23:41.926Z engine-server MONITOR: (2022-12-07T17:23:41.925Z) [myfirstchannel]: playhead: running
2022-12-07T17:23:41.926Z engine-server MONITOR: (2022-12-07T17:23:41.926Z) [myfirstchannel]: live-playhead: running
2022-12-07T17:23:42.924Z engine-server StreamSwitchLoop waited for all channels. Next tick in: 2999ms
2022-12-07T17:23:42.925Z engine-stream-switcher [myfirstchannel]: No streamSwitchManager available

Support for in-stream closed-captions

It should be possible to define a channel to passthrough closed-captions where the captions are in-stream in the source VODs, e.g.

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID="CC",LANGUAGE="eng",NAME="english",INSTREAM-ID="CC1"
#EXT-X-STREAM-INF:BANDWIDTH=9779208,AVERAGE-BANDWIDTH=8951586,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=24.000,CLOSED-CAPTIONS="CC"

Support mixing in live when in an ad break

Support mixing over to a live stream when VOD2live channel is in an ad break.
This might be achieved by always signalling a return from break (CUE-IN) when mixing over to live, but needs to be validated that this is an ok scenario for various SSAI vendors.

Bug: Duplicate Segments Appended When Previous pushAmount=-1

A bug was discovered where the same source segment was appended twice to the Session-Live output m3u8.

Normally, we expect a Live source HLS stream to always increment the Mseq after a certain amount of time.
However, for sources using CDNs or other causes of desynchronized media manifests, subsequent Media manifests could have a decrement in Mseq value instead.

Now if the proceeding media manifest would contain a Mseq value 2 counts larger than the previous Mseq value then, Session-Live would have appended a source segment it should have not appended.

eg.

Session-Live fetches Live Source Media M3U8 with Mseq=9, we set prevMseq=9, increment finished,
Session-Live fetches Live Source Media M3U8 with Mseq=10, we set prevMseq=10,
then on the next playhead ping,
Session-Live fetches Live Source Media M3U8 with Mseq=9. (Possible if a source uses unsynced CDN)
Then the number of selected segments from the Media playlist to append to the Session-Live output manifest will be calculated as
9 - 10 = -1, which means NOT to append anything... at which point the prev Mseq will be set back to 9.
then on the next playhead ping,
Session-Live fetches Live Source Media M3U8 with Mseq=11, the number of selected segments from the Media playlist to append to the Session-Live output manifest will be calculated as
11 - 9 = 2, <-- (should be 1) This looks like we went from 9 to 11, but we already got 10 before.

Bug: Instances De-sync at Switch to Live when Follower gets Bad Live Source Fetch

An issue arises when nodes switch to live and a Follower node, gets stuck in the
"ALERT! Live Source Data NOT in sync! Will try again after X ms" loop for a while.

Now, what should happen is that the Follower would have received a Live manifest that is ahead of what the Leader got when it first requested for a live manifest.
When this happens the engine will have the Follower 'drop' its manifest and use the live segments that the Leader stored in Redis instead.

This will ensure that, even though the Follower was slower in getting the correct segments, both nodes are in sync and will create the same manifests.

The Issue comes when the follower node's playhead tick interval is too long after this, relative to the live source tick interval.
By default, the tick interval is 6 seconds on the first round. Furthermore, if there was a live source fetch desync, then the tick interval would be the full 6 seconds. Normally, the tick interval time would subtract the time it took to fetch the live manifest.

During this long tick time, the leader could have already gone for another round of live segments before the follower could even read from the store. This results in the Follower missing a vital round of stored live segments, and becoming desynced with the Leader.

Add possibility to set a preroll slate on live switch

The preroll could be specified in the channel manager through a function that either fetch from some endpoint -> the slate URI or directly provides it in the code

It should be possible to let the preroll mixing happen in stream_switcher.js

Corner case when leader is loading a slate

When the leader fails to load next VOD and instead loads a slate the current VOD in the Redis db is not updated causing the two nodes to be out of sync. The other node is playing but the wrong VOD.

Leader node:

2021-06-16T07:37:04.047Z engine-session [6]: state=VOD_PLAYING (46_46, 48)
2021-06-16T07:37:04.062Z engine-session [6]: INCREMENT (mseq=40278) vodMediaSeq=(47_47 of 48)
2021-06-16T07:37:04.067Z engine-session [6]: I am the leader and updated tick interval to 4 sec
2021-06-16T07:37:04.072Z engine-session [6]: state=VOD_NEXT_INIT
2021-06-16T07:37:04.150Z engine-session [6]: got next VOD uri=https://virtual-channels-functions-alb.b17g-stage.net/stitch/master.m3u8?payload=eyJ1cmkiOiJodHRwczovL2xicy11c3AtaGxzLXZvZC5jbW9yZS5zZS92b2QvMTRmMGMvVmlsbF92aV9zYW1tYV9zYWtjYzExXzEzKDEzMzEwODA2X0lTTVVTUCkuaXNtL1ZpbGxfdmlfc2FtbWFfc2FrY2MxMV8xMygxMzMxMDgwNl9JU01VU1ApLm0zdTg/aGxzX25vX211bHRpcGxleD1mYWxzZSZmaWx0ZXI9KHR5cGUhPVwidGV4dHN0cmVhbVwiKSIsImJyZWFrcyI6W3sicG9zIjowLCJkdXJhdGlvbiI6MzAwMCwidXJsIjoiaHR0cHM6Ly90cmFpbGVyLWFkbWluLWNkbi5iMTdnLXN0YWdlLm5ldC9obHMvNjAyZjg3ZjY2MmFkMzMwMDIyNmIyNWE5L2luZGV4Lm0zdTgifSx7InBvcyI6MCwiZHVyYXRpb24iOjIwMDAwLCJ1cmwiOiJodHRwczovL3RyYWlsZXItYWRtaW4tY2RuLmIxN2cubmV0L2hscy82MGFmODRiYjNiYzM5MzAwMjc4Y2MzOTYvaW5kZXgubTN1OCJ9LHsicG9zIjowLCJkdXJhdGlvbiI6NjAwMCwidXJsIjoiaHR0cHM6Ly90cmFpbGVyLWFkbWluLWNkbi5iMTdnLm5ldC9obHMvNjBhMjJhMmVjNmRkZjQwMDQ2ODE5YzI1L2luZGV4Lm0zdTgifSx7InBvcyI6MCwiZHVyYXRpb24iOjIwMDAwLCJ1cmwiOiJodHRwczovL3RyYWlsZXItYWRtaW4tY2RuLmIxN2cubmV0L2hscy82MDkxNWZhYmQ0YWQwNTAwNjc3NjhjM2QvaW5kZXgubTN1OCJ9LHsicG9zIjowLCJkdXJhdGlvbiI6MzAwMDAsInVybCI6Imh0dHBzOi8vdHJhaWxlci1hZG1pbi1jZG4uYjE3Zy5uZXQvaGxzLzYwYTIyN2Y2OGI5ZWUxMDAzZTNjMjNmNy9pbmRleC5tM3U4In0seyJwb3MiOjAsImR1cmF0aW9uIjo4MDAwLCJ1cmwiOiJodHRwczovL3RyYWlsZXItYWRtaW4tY2RuLmIxN2cubmV0L2hscy82MDk1NDcxZGQzNDNmYTAwNTI0ZTNjMmEvaW5kZXgubTN1OCJ9LHsicG9zIjowLCJkdXJhdGlvbiI6MzAwMDAsInVybCI6Imh0dHBzOi8vdHJhaWxlci1hZG1pbi1jZG4uYjE3Zy5uZXQvaGxzLzYwYzg4MzgzZDE4MmJhMDA4MmI5YmQ1ZS9pbmRleC5tM3U4In0seyJwb3MiOjAsImR1cmF0aW9uIjoyMDAwMCwidXJsIjoiaHR0cHM6Ly90cmFpbGVyLWFkbWluLWNkbi5iMTdnLm5ldC9obHMvNjBjMzY0MWZmOGUwNTIwMDQ5YmVhM2U5L2luZGV4Lm0zdTgifSx7InBvcyI6MCwiZHVyYXRpb24iOjMwMDAsInVybCI6Imh0dHBzOi8vdHJhaWxlci1hZG1pbi1jZG4uYjE3Zy1zdGFnZS5uZXQvaGxzLzYwMmY4N2Y2NjJhZDMzMDAyMjZiMjVhOS9pbmRleC5tM3U4In1dfQ==:0
[6]: Failed to init next VOD
2021-06-16T07:37:04.212Z engine-session [6]: ReferenceError: masterManifestUri is not defined
[6]: Will insert slate
2021-06-16T07:37:04.271Z engine-session [6]: slate loaded
2021-06-16T07:37:04.312Z engine-session [6]: INCREMENT (mseq=40232) vodMediaSeq=(1_1 of 7)

Follower node:

2021-06-16T07:37:04.341Z engine-session [6]: state=VOD_PLAYING (1_1, 48)
2021-06-16T07:37:04.346Z engine-session [6]: INCREMENT (mseq=40232) vodMediaSeq=(1_1 of 48)
2021-06-16T07:37:04.347Z engine-session [6]: Current delta time (1): 0
2021-06-16T07:37:04.348Z engine-session [6]: Current playhead position (1): 4
2021-06-16T07:37:04.348Z engine-session [6]: 190461:4000:-186461ms
2021-06-16T07:37:04.348Z engine-session [6]: Requested tickInterval=-178.46800000000002s (max=6s, diffThreshold=4000msec)
2021-06-16T07:37:04.348Z engine-session [6]: (2021-06-16T07:37:04.348Z) 0.007sec in increment. Next tick in 0.5 seconds
2021-06-16T07:37:04.800Z engine-session [6]: state=VOD_PLAYING (2_2, 48)
2021-06-16T07:37:04.801Z engine-session [6]: INCREMENT (mseq=40233) vodMediaSeq=(2_2 of 48)
2021-06-16T07:37:04.802Z engine-session [6]: Current delta time (2): 0
2021-06-16T07:37:04.802Z engine-session [6]: Current playhead position (2): 8
2021-06-16T07:37:04.802Z engine-session [6]: 190915:8000:-182915ms
2021-06-16T07:37:04.802Z engine-session [6]: Requested tickInterval=-174.918s (max=6s, diffThreshold=4000msec)
2021-06-16T07:37:04.802Z engine-session [6]: (2021-06-16T07:37:04.802Z) 0.003sec in increment. Next tick in 0.5 seconds
2021-06-16T07:37:05.254Z engine-session [6]: state=VOD_PLAYING (2_2, 48)
2021-06-16T07:37:05.256Z engine-session [6]: INCREMENT (mseq=40233) vodMediaSeq=(2_2 of 48)

Occasional stuttering when switching between vod and live

There seems to be an issue where the channel engine does not fetch a new live manifest fast enough every time. This results in a small stuttering lasting about 1 second. This occurs maybe once or twice per hour when using this as a schedule source https://schedule.vc.eyevinn.technology/api/v1.
This needs to be further investigated to more precisely determine the cause and how to fix it.

Ability to Get a Schedule given a Channel ID

Currently in stream_switcher.js we extract the schedule from the streamSwitchManager through the function getSchedule().
We need to extend this function and stream_switcher.js to handle getting channel-specific schedules, i.e.

await this.streamSwitchManager.getSchedule(this.sessionId);

Finally, the actual function in reference StreamSwitchManager needs to be updated to handle this new input argument.

SessionLive: Media Playlist - Slide Window Based On Total Duration Rather Than Number of Items

Currently, the manifests returned from sessionLive.js, slide the window of playlist segments based on item count.
eg. if target_count is 10 and 2 new segments are added, then sessionLive will release the 2 top-most segments.
Media-Sequence increments by 2.

This is different from how session.js (hls-vodtolive) does it, where it releases segments based on the total segment duration of all segments in the playlist.
eg. if target_duration is 60s. Current playlist contains 10 segments each 6s long, and 2 new segments (3s duration each) are added to the playlist, then only 1 top-most segment would be released since: 60 + 3 + 3 - 6 = target_duration
Media-Sequence increments by 1.

Having different rules in session and sessionLive poses some issues when mix-switching back, if the durations of the segments in v2l are much shorter than live

Suggest implementing the same rules in sessionLive as in session!

Add new public functions for getting all types of manifests given a channel Id

We need an alternative for getting the engine's master, media & audio manifests that do not involve the server end-points.

These manifest can be generated directly in new functions in server.js

i.e
async engine.getMasterManifest(channelId)
async engine.getMediaManifests(channelId)
async engine.getAudioManifests(channelId)

Note, the latter 2 functions should return an object containing all media/audio manifests.

Bug: SessionLive selects different variants compared to Session

When switching to either vod2live or live2live, a client may receive a manifest from the engine that has different segment URLs because the segment URLs are for a different variant than the manifest from before. This is due to the fact that SessionLive (which has a manifest builder function in it) chooses/filters variants differently from Session, which actually uses a function in @eyevinn/hls-vodtolive when filtering and building manifests.

Suggest adding the same choosing logic to SessionLive's function.

Player stops for demuxed audio if fragments duration is different

HLS player stops after 2-3 videos for HLS stream which has demuxed audio with a slightly different #EXINF values: for video it is 6.006 while for audio it is 6.016.
You can reproduce it using these two manifests:
https://amsrmpdevwe-euwe.streaming.media.azure.net/94f0df66-d92d-4d21-815a-756a2a00d186/5882_b4d.ism/manifest(format=m3u8-aapl)
https://amsrmpdevwe-euwe.streaming.media.azure.net/5237a941-7d05-4c56-82bd-c4f51322b43e/5614_0a0.ism/manifest(format=m3u8-aapl)

I've checked videos from your server-demuxed.js demo script and found that audio and video segments durations are equal. So I suspect that there is a root cause. But I am not sure.

BUG: Playhead Tick Compensation Logic Blocked By Low MaxTickInterval

In a ChannelEngine's engineOptions, when the maxTickInterval is set lower than the largest expected segment duration - or when the largest segment duration is higher than the default maxTickInterval of 10 seconds, then a playback issue may occur after some time.

When the maxTickInterval is lower then the tickInterval in session.startPlayheadAsync() then the internal playhead tick interval duration will be set too low, depending on the difference between the tick and the maxTick.

This will result in incrementing the channel's v2l stream media-sequences too early. The playhead will know that it is too early and will try to compensate by extending the next tickInterval, padding some extra time. However, it can not compensate as it is limited to the max value.

Consider the example of running the channel engine with assets with segments of 6000ms duration, and with a maxTickInterval set to 5000ms.

The channel-engine Playhead will step (or iterate) after 5000ms, when it should have done it after 6000ms. On the next iteration, depending on the set playheadDiffThreshold value, the diff will be added to the next tick duration as an attempt to compensate and get in sync with the asset. e.i. 6000+1000=7000. But 7000 is also greater than the max and the tick interval will be lowered back to 5000ms.
On the next iteration, the Playhead will try to compensate by 2000ms, e.i. 6000+2000=8000. But again the max value will be used instead.

The difference will accumulate over time and the result will have the channel-engine step through media-sequences too fast, consuming the vod asset earlier than expected. An unwanted side-effect is that some players might not handle this livestream behavior gracefully and will just stop playback altogether.

Handle Rejection from StreamSwitcher

Currently, when a session's streamSwitcher gets a rejection from
... = await this.streamSwitchManager.getSchedule(this.sessionId); it is thrown to the top level at server.js to function
StreamSwitchLoop(...) which doesn't handle rejection cases.

This could cause the function to end and thus no more calls to the streamSwitcher are made. Freezing the streamSwitch status

Optimize live source fetch retry

Currently, when LIVE and fetching live manifests for each variant of the live source stream, and the fetched manifests are not on the same media sequence, then it will fetch again EVERY variant manifest from the source until the served manifests are all matching in media sequence.

The problem is that it it does not keep any manifests from the previous tries. So what sometimes happens, and contributes to long time spent fetching, is that the media sequence for a variant might step again forcing another retry.

eg.

Fetched manifest media sequences -> [99, 99, 100]

Not lined up, try ALL variants again...

Fetched manifest media sequences -> [100, 99, 100]

Not lined up, try ALL variants again...

Fetched manifest media sequences -> [100, 100, 101]

Not lined up, try ALL variants again...

etc.

We should instead only fetch again the variants that have sequences lower than the max sequence.

Feeds go to slate after one day (or end of feed)

Hi,

I've been working with the channel-engine to implement a vod-to-live service for our website. It seems like when the the channel-engine reaches the end of the feed, though, it just goes to slate and doesn't seem to be able to recover or loop. This is also true after I implemented a "schedule" which basically loops the vod library until it reaches 24 hours. In this case, the channel engine seems to go to slate after 24 hours.

Is there a flag for looping content, or some other method? Any help would be greatly appreciated.

Thank you!

Support for node v18

Channel Engine fails to start with node version 18 and bails with the following error

TypeError: Cannot set property closed of #<Readable> which has only a getter
    at patch

Seems to be related to the NPM module restify that is being used: restify/node-restify#1888

Support for subtitles

  • Slice the webvtt media playlist into media sequences aligned with video.
  • Update master manifest response with “virtual” subtitle tracks referenced. Requires to define a predefined set of languages per channel
  • Match available subtitle tracks in VOD with the predefined set of languages per channel. And provide empty / “black” for those tracks without a match
  • Provide a subtitle playlist endpoint that is aligned with the media sequence of video

CUE-IN tag must always be in front of the bumper segments

Currently, when switching from V2L->LIVE, the bumper-segments are stiched in between the V2L segments and the LIVE segments with a CUE-IN tag placed after the bumper segment.

This was not an expected nor wanted outcome because it would mean that the bumper segment is a part of the supposed AD break, which it isn't. This needs to be fixed!

However, on a LIVE->V2L switch, the CUE-IN tag is placed correctly (before the bumper segment)

Ad insertion into live video stream

Is it possible to generate Playlist on the go while live video source is available when ever we want to switch live source we can switch to.

Just like we normally do in rundown broadcast playout.

We are looking for a solution that can do playout live video source and inject commercials into live stream in user friendly manners.

Regards,

Fahad
Skype :sfahadshahzad

Placement of EXT-X-CUE-IN seems wrong

Though we set DURATION on EXT-X-CUE-OUT I am not sure if this is critical or a new issue that has been introduced in v3 but interesting to have a look at. When having VOD's with cue markers we get the following in the resulting vod2live stream:

https://maitv-vod.lab.eyevinn.technology/VINN.mp4/1000/1000-00012.ts
#EXTINF:1.240,
https://maitv-vod.lab.eyevinn.technology/VINN.mp4/1000/1000-00013.ts
#EXT-X-DISCONTINUITY
#EXTINF:11.000,
https://lab.cdn.eyevinn.technology/THE_GRAND_BUDAPEST_HOTEL_Trailer_2014.mp4/manifest_1_00001.ts
#EXT-X-CUE-IN

where the placement of EXT-X-CUE-IN looks a bit strange. Maybe it is correct according to the standard but needs to be verified whether it shouldn't be placed before the

#EXTINF:11.000,
https://lab.cdn.eyevinn.technology/THE_GRAND_BUDAPEST_HOTEL_Trailer_2014.mp4/manifest_1_00001.ts

instead.

Extend '/reset' endpoint to also reset session-live, and streamswitcher states

When using the /reset endpoint, currently only session is being reset. session-live and streamswitchers need to be reset too.

session-live already has a resetAsync() function. Just needs to call it in handler function.
streamswitcher statuses will need to set switcherStatus[channel] = null | false to count as resetted

manifest filtering- requires double-encoding of & to properly get through

I've only been able to get this to work using a string like %28type%3D%3D"video"%2526%2526height<1000%29%2526%2526%28type%3D%3D"video"%2526%2526height>0%29

where you can see the double encoding of the ampersands %2526

Raw:
(type=="video"&&height<1000)&&(type=="video"&&height>0)

Pre encoded
(type=="video"%26%26height<1000)%26%26(type=="video"%26%26height>0)

Fully encoded
%28type%3D%3D"video"%2526%2526height<1000%29%2526%2526%28type%3D%3D"video"%2526%2526height>0%29

otherwise the express/req middleware breaks up
req.query['filter'] = "(type="video""
req.query['height<1000'] = '';

identified and confirmed in engine/server.js line 234
if (req.query['filter']) {
debug(Applying filter on master manifest ${req.query['filter']});
filter = filterQueryParser(req.query['filter']);
}

Add Option For Setting A Diff Compensation Rate

Currently, in session.js, when adding extra time to the tick interval based on the external difference compensation, the rate is set to DIFF_CORRECTION_RATE=0.5 and is hardcoded.

          // Apply external diff compensation if available.
          if (this.diffCompensation && this.diffCompensation > 0) {
            const DIFF_COMPENSATION = (reqTickInterval * DIFF_CORRECTION_RATE).toFixed(2) * 1000;
            debug(`[${this._sessionId}]: Adding ${DIFF_COMPENSATION}msec to tickInterval to compensate for schedule diff (current=${this.diffCompensation}msec)`);
            tickInterval += (DIFF_COMPENSATION / 1000);
            this.diffCompensation -= DIFF_COMPENSATION;
          }

Would be better to have it be another engine option like forcedTargetDuration so that it can be adjusted externally.

Support SGAI by inserting HLS interstitials

It should be possible to configure a channel to insert HLS-interstitial tags for a live ad break in a V2L channel. You configure ad serving endpoint to be used. The V2L channel also contains a slate for the as break that is either replaced downstream by SSAI or client side.

Time between Media Playlist loading tries are too long when live-source has short segment durations

Currently, when SessionLive is fetching/loading media playlists from the live-source, and they do not all comeback with the same
#EXT-X-MEDIA-SEQUENCE value, then they are to retry the manifest loading operation after waiting 1500ms.

However, for a source live stream with segment durations <4s, 1500ms might be too long, causing us to miss the window where the media playlists were all synced up.
eg.
... SessionLive fetches media playlist for all variants. Gets variant_1 w/ mseq:11, and variant_2 w/ mseq:12
... Not in sync! Try again after 1500ms
... SessionLive fetches media playlist for all variants. Gets variant_1 w/ mseq:12, and variant_2 w/ mseq:13

We missed the window when both were w/ mseq:12

I suggest that we have the time to wait depending on the duration of the newest Live source segment.

MediaTailor support

In order to support how AWS MediaTailor (SSAI) access the channel origin the following needs to be implemented.
Today a channel is accessed with the following URL: http://<engine>/live/master.m3u8?channel=1
and to adapt to MediaTailor an additional endpoint (alias) in the following form is needed http://<engine>/live/1/master.m3u8 which would translate to the same above.

Scheduled for next 2.minor-release which is currently main/master.

Back-off live schedule polling during an ongoing event

Currently the getSchedule() from the stream switch manager is called quite frequently. Reduce this frequency by changing the interval during an ongoing event. Around end of an event this frequency can be increased to handle late changes in schedule.

Switcher Gets Stuck in busy/'working' State When an Error is Caught in Function

Recently we added try-catch blocks in the function _initSwitching(..)
To have manifest requesting clients wait for the _initSwitching(..) to complete a switch, a boolean is set to true at the beginning of the switching process.
Now if a switch process fails, the error is caught and thrown to the upper levels. But right now the boolean is not set to false when this happens, fooling the StreamSwitcher into thinking _initSwitching(..) is still busy processing a switch.

Support for push HLS to AWS MediaPackage

A proof-of-concept on how to apply DRM protection on a channel by adding the support for the playhead to push the generated manifest to an AWS MediaPackage channel.

Will introduce a separate service (probably another repo) that sits on the origin (or close) to and pull HLS (manifest and segments) and push to the origin.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.