Statistics
| Branch: | Revision:

chunker-player / chunker_player / chunker_player.c @ eed0812a

History | View | Annotate | Download (20.8 KB)

1
/*
2
 *  Copyright (c) 2009-2011 Carmelo Daniele, Dario Marchese, Diego Reforgiato, Giuseppe Tropea
3
 *  developed for the Napa-Wine EU project. See www.napa-wine.eu
4
 *
5
 *  This is free software; see lgpl-2.1.txt
6
 */
7

    
8
#include <stdio.h>
9
#include <unistd.h>
10
#include <SDL.h>
11
#include <SDL_mutex.h>
12
#include "player_defines.h"
13
#include <confuse.h>
14
#include "http_default_urls.h"
15
#include "player_defines.h"
16
#include "chunker_player.h"
17
#include "chunk_puller.h"
18
#include "player_gui.h"
19
#include <time.h>
20
#include <getopt.h>
21

    
22
#ifdef PSNR_PUBLICATION
23
#include <event2/event.h>
24
#include <napa_log.h>
25
#endif
26

    
27
#ifdef CHANNELS_DOWNLOAD
28
#include "http.h"
29
#endif
30

    
31
#ifdef _WIN32
32
#include <windows.h>
33
#endif
34

    
35
#ifdef __linux__
36
#include <X11/Xlib.h>
37
#endif
38

    
39
int NChannels;
40
char StreamerFilename[255];
41
char *ConfFilename = NULL;
42
int Port;
43

    
44
int ParseConf(char *file, char *uri);
45
int SwitchChannel(SChannel* channel);
46

    
47
int ReadALine(FILE* fp, char* Output, int MaxOutputSize)
48
{
49
    int i=0;
50
    int c;
51
    do
52
    {
53
        c=getc(fp);
54
        if(c=='\r' || c=='\n' || c==EOF)
55
        {
56
            Output[i]=0;
57
            return i;
58
        }
59
        Output[i++]=c;
60
    }
61
    while(c!=EOF);
62
    
63
    return -1;
64
}
65

    
66
int CheckForRepoAddress(char* Param)
67
{
68
        int result = 0;
69
    int i, Found=0;
70

    
71
    if(strncasecmp(Param,"repo_address=",13)==0)
72
    {
73
        result=1;
74
        //find ',' in Param (if exist)
75
        int len=strlen(Param);
76
        char* tmp=(char*)calloc(1,len);
77
        if(tmp)
78
        {
79
            for(i=13;i<len;i++)
80
            {
81
                if(Param[i]==',')
82
                {
83
                    Found=1;
84
                    break;
85
                }
86
                tmp[i-13]=Param[i];
87
            }
88

    
89
            if(i==len || Found) strncpy(RepoAddress,tmp,2048);
90
            free(tmp);
91
        }
92
    }
93

    
94
        return result;
95
}
96

    
97
void sigproc()
98
{
99
        printf("you have pressed ctrl-c, terminating...\n");
100
        quit = 1;
101
}
102

    
103
static void print_usage(int argc, char *argv[])
104
{
105
  fprintf (stderr,
106
    "\nUsage:%s [options]\n"
107
    "\n"
108
    "\t[-c ChannelName]: channel name (from channels.conf)\n"
109
    "\t[-C file]: channel list file name (default: channels.conf)\n"
110
    "\t[-p port]: player http port\n"
111
    "\t[-q q_thresh]: playout queue size\n"
112
    "\t[-A audiocodec]\n"
113
    "\t[-V videocodec]\n"
114
    "\t[-t]: log traces (WARNING: old traces will be deleted).\n"
115
    "\t[-s mode]: silent mode (no GUI) (mode=1 audio ON, mode=2 audio OFF, mode=3 audio OFF; P2P OFF).\n\n"
116
    "=======================================================\n", argv[0]
117
    );
118
}
119

    
120
// initialize a receiver instance for receiving chunks from a Streamer process
121
// returns: <0 on error
122
int initIPCReceiver(Port)
123
{
124
#ifdef HTTPIO
125
        struct MHD_Daemon *daemon = NULL;
126
        //this thread fetches chunks from the network by listening to the following path, port
127
        daemon = (struct MHD_Daemon*)initChunkPuller(UL_DEFAULT_EXTERNALPLAYER_PATH, Port);
128
        if(daemon == NULL)
129
        {
130
                printf("CANNOT START MICROHTTPD SERVICE, EXITING...\n");
131
                return -1;
132
        }
133
#endif
134
#ifdef TCPIO
135
        int fd = initChunkPuller(Port);
136
        if(! (fd > 0))
137
        {
138
                printf("CANNOT START TCP PULLER...\n");
139
                return -1;
140
        }
141
#endif
142

    
143
        return 1;
144
}
145

    
146
int main(int argc, char *argv[])
147
{
148
        srand ( time(NULL) );
149
#ifdef __linux__
150
        XInitThreads();
151
#endif
152
        // some initializations
153
        SilentMode = 0;
154
        queue_filling_threshold = 5;
155
        quit = 0;
156
        QueueFillingMode=1;
157
        LogTraces = 0;
158
        qoe_led = 1;
159
        scale_with_sdl = SCALE_WITH_SDL_DEFAULT;
160

    
161
        NChannels = 0;
162
        SelectedChannel = -1;
163
        char firstChannelName[255];
164
        int firstChannelIndex;
165
        
166
        firstChannelName[0] = 0;
167
        memset((void*)Channels, 0, (MAX_CHANNELS_NUM*sizeof(SChannel)));
168

    
169
        Port = 6100;
170

    
171
        SDL_Event event;
172
        OverlayMutex = SDL_CreateMutex();
173
        
174
        char c;
175
        while ((c = getopt (argc, argv, "q:c:C:p:s:t")) != -1)
176
        {
177
                switch (c) {
178
                        case 0: //for long options
179
                                break;
180
                        case 'q':
181
                                sscanf(optarg, "%d", &queue_filling_threshold);
182
                                break;
183
                        case 'c':
184
                                sprintf(firstChannelName, "%s", optarg);
185
                                break;
186
                        case 'C':
187
                                ConfFilename = strdup(optarg);
188
                                break;
189
                        case 'p':
190
                                sscanf(optarg, "%d", &Port);
191
                                break;
192
                        case 's':
193
                                sscanf(optarg, "%d", &SilentMode);
194
                                break;
195
                        case 't':
196
                                DELETE_DIR("traces");
197
                                CREATE_DIR("traces");
198
                                LogTraces = 1;
199
                                break;
200
                        default:
201
                                print_usage(argc, argv);
202
                                return -1;
203
                }
204
        }
205

    
206
#ifdef EMULATE_CHUNK_LOSS
207
        ScheduledChunkLosses = NULL;
208
        cfg_opt_t scheduled_chunk_loss_opts[] =
209
        {
210
                CFG_INT("Time", 0, CFGF_NONE),
211
                CFG_INT("Value", 0, CFGF_NONE),
212
                CFG_INT("MinValue", 0, CFGF_NONE),
213
                CFG_INT("MaxValue", 0, CFGF_NONE),
214
                CFG_INT("Burstiness", 0, CFGF_NONE),
215
                CFG_END()
216
        };
217
        cfg_opt_t opts[] =
218
        {
219
                CFG_SEC("ScheduledChunkLoss", scheduled_chunk_loss_opts, CFGF_MULTI),
220
                CFG_END()
221
        };
222
        cfg_t *cfg, *cfg_sched;
223
        cfg = cfg_init(opts, CFGF_NONE);
224
        if(!cfg_parse(cfg, "_chunklossrate.conf") == CFG_PARSE_ERROR)
225
        {
226
                NScheduledChunkLosses = cfg_size(cfg, "ScheduledChunkLoss");
227
                if(NScheduledChunkLosses > 0)
228
                        ScheduledChunkLosses = (SChunkLoss*)malloc((NScheduledChunkLosses)*sizeof(SChunkLoss));
229
                
230
                int j;
231
                for(j = 0; j < cfg_size(cfg, "ScheduledChunkLoss"); j++)
232
                {
233
                        cfg_sched = cfg_getnsec(cfg, "ScheduledChunkLoss", j);
234
                        ScheduledChunkLosses[j].Time = cfg_getint(cfg_sched, "Time");
235
                        ScheduledChunkLosses[j].Value = cfg_getint(cfg_sched, "Value");
236
                        ScheduledChunkLosses[j].Burstiness = cfg_getint(cfg_sched, "Burstiness");
237
                        
238
                        // -1 means random value between min and max
239
                        if(ScheduledChunkLosses[j].Value == -1)
240
                        {
241
                                ScheduledChunkLosses[j].MinValue = cfg_getint(cfg_sched, "MinValue");
242
                                ScheduledChunkLosses[j].MaxValue = cfg_getint(cfg_sched, "MaxValue");
243
                        }
244
                }
245
                cfg_free(cfg);
246
                CurrChunkLossIndex = -1;
247
                
248
                for(j=0; j < NScheduledChunkLosses; j++)
249
                {
250
                        printf("ScheduledChunkLosses[%d].Time = %ld\n", j, ScheduledChunkLosses[j].Time);
251
                        printf("ScheduledChunkLosses[%d].Value = %d\n", j, ScheduledChunkLosses[j].Value);
252
                        printf("ScheduledChunkLosses[%d].Burstiness = %d\n", j, ScheduledChunkLosses[j].Burstiness);
253
                }
254
        }
255
#endif
256

    
257
        if (initIPCReceiver(Port) < 0) {
258
                exit(2);
259
        }
260

    
261
#ifdef PSNR_PUBLICATION
262
        repoclient=NULL;
263
        LastTimeRepoPublish.tv_sec=0;
264
        LastTimeRepoPublish.tv_usec=0;
265
        eventbase = event_base_new();
266
        napaInitLog(LOG_DEBUG, NULL, NULL);
267
        repInit("");
268
#endif
269

    
270
        if(SilentMode == 0)
271
        {
272
                if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
273
                        fprintf(stderr, "Could not initialize SDL audio/video or timer - %s\n", SDL_GetError());
274
                        return -1;
275
                }
276
        }
277
        else if(SilentMode == 1)
278
        {
279
                if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
280
                        fprintf(stderr, "Could not initialize SDL audio or timer - %s\n", SDL_GetError());
281
                        return -1;
282
                }
283
        }
284
        else
285
        {
286
                if(SDL_Init(SDL_INIT_TIMER)) {
287
                        fprintf(stderr, "Could not initialize SDL timer - %s\n", SDL_GetError());
288
                        return -1;
289
                }
290
        }
291

    
292
        if (ConfFilename) {
293
                if(ParseConf(ConfFilename, NULL))
294
                {
295
                        printf("ERROR: Cannot parse configuration file %s, exit...\n", ConfFilename);
296
                        exit(1);
297
                }
298
        } else {
299
                if(ParseConf(DEFAULT_CONF_FILENAME, DEFAULT_CONF_URI))
300
                {
301
                        printf("ERROR: Cannot parse configuration file, exit...\n");
302
                        exit(1);
303
                }
304
        }
305

    
306
        firstChannelIndex = -1;
307
        int it;
308
        for(it = 0; it < NChannels; it++)
309
        {
310
                if(firstChannelName[0] == 0) {
311
                        firstChannelIndex = 0;
312
                        break;
313
                } else if (!strcmp(Channels[it].Title, firstChannelName))
314
                {
315
                        firstChannelIndex = it;
316
                        break;
317
                }
318
        }
319
        
320
        if(firstChannelIndex < 0)
321
        {
322
                printf("Cannot find the specified channel (%s) in the configuration file (channels.conf), exiting\n", firstChannelName);
323
                exit(0);
324
        }
325
        
326
        if(ChunkerPlayerGUI_Init())
327
        {
328
                printf("ERROR: Cannot init player gui, exit...\n");
329
                exit(1);
330
        }
331
        
332
        SelectedChannel = firstChannelIndex;
333

    
334
        SwitchChannel(&(Channels[SelectedChannel]));
335

    
336
        // Wait for user input
337
        while(!quit) {
338
                if(QueueFillingMode) {
339
                        if(ChunkerPlayerCore_AudioEnded())
340
                                ChunkerPlayerCore_ResetAVQueues();
341

    
342
#ifdef DEBUG_QUEUE
343
                        //printf("QUEUE: MAIN audio:%d video:%d audiolastframe:%d videolastframe:%d\n", audioq.nb_packets, videoq.nb_packets, audioq.last_frame_extracted, videoq.last_frame_extracted);
344
#endif
345
                }
346
                
347
#ifdef PSNR_PUBLICATION
348
                event_base_loop(eventbase, EVLOOP_NONBLOCK);
349
#endif
350

    
351
                //listen for key and mouse
352
                while(SDL_PollEvent(&event)) {
353
                        switch(event.type) {
354
                                case SDL_QUIT:
355
                                        quit=1;
356
                                break;
357
                                case SDL_VIDEORESIZE:
358
                                        if(SilentMode)
359
                                                break;
360
                                        // printf("\tSDL_VIDEORESIZE event received!! \n");
361
                                        if(!FullscreenMode)
362
                                                ChunkerPlayerGUI_HandleResize(event.resize.w, event.resize.h);
363
                                        else
364
                                                ChunkerPlayerGUI_HandleResize(FullscreenWidth, FullscreenHeight);
365
                                break;
366
                                case SDL_ACTIVEEVENT:
367
                                        if(SilentMode)
368
                                                break;
369
                                                
370
                                        // if the window was iconified or restored
371
                                        if(event.active.state & SDL_APPACTIVE)
372
                                        {
373
                                                //If the application is being reactivated
374
                                                if( event.active.gain != 0 )
375
                                                {
376
                                                        ChunkerPlayerGUI_HandleGetFocus();
377
                                                }
378
                                        }
379

    
380
                                        //If something happened to the keyboard focus
381
                                        else if( event.active.state & SDL_APPINPUTFOCUS )
382
                                        {
383
                                                //If the application gained keyboard focus
384
                                                if( event.active.gain != 0 )
385
                                                {
386
                                                        ChunkerPlayerGUI_HandleGetFocus();
387
                                                }
388
                                        }
389
                                        //If something happened to the mouse focus
390
                                        else if( event.active.state & SDL_APPMOUSEFOCUS )
391
                                        {
392
                                                //If the application gained mouse focus
393
                                                if( event.active.gain != 0 )
394
                                                {
395
                                                        ChunkerPlayerGUI_HandleGetFocus();
396
                                                }
397
                                        }
398
                                        break;
399
                                case SDL_MOUSEMOTION:
400
                                        if(SilentMode)
401
                                                break;
402
                                                
403
                                        ChunkerPlayerGUI_HandleMouseMotion(event.motion.x, event.motion.y);
404
                                break;
405
                                case SDL_MOUSEBUTTONUP:
406
                                        if(SilentMode)
407
                                                break;
408
                                                
409
                                        if( event.button.button != SDL_BUTTON_LEFT )
410
                                                break;
411

    
412
                                        ChunkerPlayerGUI_HandleLButton(event.motion.x, event.motion.y);
413
                                break;
414
                                case SDL_KEYDOWN:  /* Handle a KEYDOWN event */
415
                                        switch( event.key.keysym.sym ){
416
                                                case SDLK_ESCAPE:
417
                                                        if(FullscreenMode) {
418
                                                                ChunkerPlayerGUI_ToggleFullscreen();
419
                                                        }
420
                                                        break;
421
                                                case SDLK_r:
422
                                                        ChunkerPlayerGUI_ChangeRatio();
423
                                                        break;
424
                                                case SDLK_q:
425
                                                        qoe_led = !qoe_led;
426
                                                        break;
427
                                                case SDLK_x:
428
                                                        scale_with_sdl = !scale_with_sdl;
429
                                                        break;
430
                                                case SDLK_f:
431
                                                        ChunkerPlayerGUI_ToggleFullscreen();
432
                                                        break;
433
                                                case SDLK_UP:
434
                                                        ZapUp();
435
                                                        break;
436
                                                case SDLK_DOWN:
437
                                                        ZapDown();
438
                                                        break;
439
                                                case SDLK_LEFT:
440
                                                        ChunkerPlayerCore_ChangeDelay(100);
441
                                                        break;
442
                                                case SDLK_RIGHT:
443
                                                        ChunkerPlayerCore_ChangeDelay(-100);
444
                                                        break;
445
                                                default:
446
                                                        break;
447
                                        }
448
                                break;
449
                        }
450
                        ChunkerPlayerGUI_HandleKey();
451
                }
452
                usleep(120000);
453
        }
454

    
455
        KILL_PROCESS(&(Channels[SelectedChannel].StreamerProcess));
456

    
457
        //TERMINATE
458
        ChunkerPlayerCore_Stop();
459
        ChunkerPlayerCore_Finalize();
460
        ChunkerPlayerGUI_Close();
461
        SDL_DestroyMutex(OverlayMutex);
462
        SDL_Quit();
463
        
464
#ifdef HTTPIO
465
        finalizeChunkPuller(daemon);
466
#endif
467
#ifdef TCPIO
468
        finalizeChunkPuller();
469
#endif
470
        
471
#ifdef EMULATE_CHUNK_LOSS
472
        if(ScheduledChunkLosses)
473
                free(ScheduledChunkLosses);
474
#endif
475

    
476
#ifdef PSNR_PUBLICATION
477
        if(repoclient) repClose(repoclient);        event_base_free(eventbase);
478
#endif
479
        return 0;
480
}
481

    
482
int cb_validate_conffile(cfg_t *cfg)
483
{
484
        char LaunchString[255];
485
        cfg_t *cfg_greet;
486
        
487
        if(cfg_size(cfg, "Channel") == 0)
488
        {
489
                cfg_error(cfg, "no \"Channel\" section found");
490
                return -1;
491
        }
492
        
493
        printf("\t%d Channel setions found\n", cfg_size(cfg, "Channel"));
494
        
495
        int j;
496
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
497
        {
498
                cfg_greet = cfg_getnsec(cfg, "Channel", j);
499
                sprintf(LaunchString, "%s", cfg_getstr(cfg_greet, "LaunchString"));
500
                if(!(strlen(LaunchString) > 0))
501
                {
502
                        cfg_error(cfg, "invalid LaunchString for Channel[%d]", j);
503
                        return -1;
504
                }
505
                printf("\tChannel[%d].LaunchString = %s\n", j, LaunchString);
506
                printf("\tChannel[%d].AudioChannels = %ld\n", j, cfg_getint(cfg_greet, "AudioChannels"));
507
                printf("\tChannel[%d].SampleRate = %ld\n", j, cfg_getint(cfg_greet, "SampleRate"));
508
                printf("\tChannel[%d].Width = %ld\n", j, cfg_getint(cfg_greet, "Width"));
509
                printf("\tChannel[%d].Height = %ld\n", j, cfg_getint(cfg_greet, "Height"));
510
                printf("\tChannel[%d].Bitrate = %ld\n", j, cfg_getint(cfg_greet, "Bitrate"));
511
                printf("\tChannel[%d].Ratio = %s\n", j, cfg_getstr(cfg_greet, "Ratio"));
512
        }
513
    return 0;
514
}
515

    
516
int ParseConf(char *file, char *uri)
517
{
518
        int j,r;
519
        char * conf = NULL;
520

    
521
        // PARSING CONF FILE
522
        cfg_opt_t channel_opts[] =
523
        {
524
                CFG_STR("Title", "", CFGF_NONE),
525
                CFG_STR("ChannelGroup", "", CFGF_NONE),
526
                CFG_STR("LaunchString", "", CFGF_NONE),
527
                CFG_INT("AudioChannels", 2, CFGF_NONE),
528
                CFG_INT("SampleRate", 48000, CFGF_NONE),
529
                CFG_INT("Width", 176, CFGF_NONE),
530
                CFG_INT("Height", 144, CFGF_NONE),
531
                CFG_INT("Bitrate", 0, CFGF_NONE),
532
                CFG_STR("VideoCodec", "mpeg4", CFGF_NONE),
533
                CFG_STR("AudioCodec", "mp3", CFGF_NONE),
534
                
535
                // for some reason libconfuse parsing for floating point does not work in windows
536
                //~ CFG_FLOAT("Ratio", 1.22, CFGF_NONE),
537
                CFG_STR("Ratio", "1.22", CFGF_NONE),
538
                CFG_END()
539
        };
540
        cfg_opt_t opts[] =
541
        {
542
                CFG_SEC("Channel", channel_opts, CFGF_TITLE | CFGF_MULTI),
543
                CFG_END()
544
        };
545
        cfg_t *cfg, *cfg_channel;
546
        cfg = cfg_init(opts, CFGF_NONE);
547

    
548
#ifdef CHANNELS_DOWNLOAD
549
        if (uri) {
550
                http_get2file(uri, file);
551
        }
552
#endif
553

    
554
        r = cfg_parse(cfg, file);
555
        if (r == CFG_PARSE_ERROR) {
556
                printf("Error while parsing configuration file, exiting...\n");
557
                cb_validate_conffile(cfg);
558
                return 1;
559
        } else if (r == CFG_FILE_ERROR) {
560
                printf("Error trying parsing configuration file. '%s' couldn't be opened for reading\n", file);
561
                return 1;
562
        }
563

    
564
        FILE * tmp_file;
565
        if( (tmp_file = fopen(DEFAULT_PEEREXECNAME_FILENAME, "r")) ) {
566
                if(fscanf(tmp_file, "%s", StreamerFilename) != 1) {
567
                        printf("Wrong format of conf file %s containing peer application exec name. Assuming default: %s.\n\n", DEFAULT_PEEREXECNAME_FILENAME, DEFAULT_PEER_EXEC_NAME);
568
                        strncpy(StreamerFilename, DEFAULT_PEER_EXEC_NAME, 255);
569
                }
570
                fclose(tmp_file);
571
        }
572
        else {
573
                printf("Could not find conf file %s containing peer application exec name. Exiting.\n\n", DEFAULT_PEEREXECNAME_FILENAME);
574
                exit(1);
575
        }
576
        if( (tmp_file = fopen(StreamerFilename, "r")) )
577
    {
578
        fclose(tmp_file);
579
    }
580
    else
581
        {
582
                printf("Could not find peer application (named '%s') into the current folder, please copy or link it into the player folder, then retry\n\n", StreamerFilename);
583
                exit(1);
584
        }
585
        
586
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
587
        {
588
                cfg_channel = cfg_getnsec(cfg, "Channel", j);
589
                sprintf(Channels[j].Title, "%s", cfg_title(cfg_channel));
590
                strcpy(Channels[j].ChannelGroup, cfg_getstr(cfg_channel, "ChannelGroup"));
591
                if (strlen(Channels[j].ChannelGroup) == 0) strcpy(Channels[j].ChannelGroup,Channels[j].Title);
592
                strcpy(Channels[j].LaunchString, cfg_getstr(cfg_channel, "LaunchString"));
593
                strcpy(Channels[j].VideoCodec, cfg_getstr(cfg_channel, "VideoCodec"));
594
                strcpy(Channels[j].AudioCodec, cfg_getstr(cfg_channel, "AudioCodec"));
595
                Channels[j].Width = cfg_getint(cfg_channel, "Width");
596
                Channels[j].Height = cfg_getint(cfg_channel, "Height");
597
                Channels[j].AudioChannels = cfg_getint(cfg_channel, "AudioChannels");
598
                Channels[j].SampleRate = cfg_getint(cfg_channel, "SampleRate");
599
                Channels[j].Ratio = strtof(cfg_getstr(cfg_channel, "Ratio"), 0);
600
                Channels[j].Bitrate = cfg_getint(cfg_channel, "Bitrate");
601
                
602
                Channels[j].Index = j+1;
603
                NChannels++;
604
        }
605
        cfg_free(cfg);
606

    
607
        return 0;
608
}
609

    
610
int ReTune(SChannel* channel)
611
{        
612
        if(ChunkerPlayerCore_IsRunning())
613
                ChunkerPlayerCore_Pause();
614
        
615
        //reset quality info
616
        channel->startTime = time(NULL);
617
        
618
        ChunkerPlayerCore_Play();
619
        
620
        return 0;
621
}
622

    
623
int StartStreamer(SChannel* channel)
624
{
625
        char argv0[255], parameters_string[511];
626
        sprintf(argv0, "%s", StreamerFilename);
627

    
628
#ifdef HTTPIO
629
        sprintf(parameters_string, "%s %s %s %d %s %s %d", "-C", channel->Title, "-P", (Port+channel->Index), channel->LaunchString, "-F", Port);
630
#endif
631

    
632
#ifdef TCPIO
633
        sprintf(parameters_string, "%s %s %s %d %s %s tcp://127.0.0.1:%d", "-C", channel->Title, "-P", (Port+channel->Index), channel->LaunchString, "-F", Port);
634
#endif
635

    
636
        printf("OFFERSTREAMER LAUNCH STRING: %s %s\n", argv0, parameters_string);
637

    
638
        if(SilentMode != 3) //mode 3 is without P2P peer process
639
        {
640

    
641
#ifndef __WIN32__
642
                int i;
643
                char* parameters_vector[255];
644
                parameters_vector[0] = argv0;
645

    
646
                RepoAddress[0]='\0';
647

    
648
                // split parameters and count them
649
                int par_count=1;
650
                char* pch = strtok (parameters_string, " ");
651
                while (pch != NULL)
652
                {
653
                        if(par_count > 255) break;
654
                        //printf ("\tpch=%s\n",pch);
655
                        parameters_vector[par_count] = strdup(pch);
656
                        // Find repo_address
657
                        CheckForRepoAddress(parameters_vector[par_count]);
658
                        pch = strtok (NULL, " ");
659
                        par_count++;
660
                }
661
                parameters_vector[par_count] = NULL;
662

    
663
                int d;
664
                int stdoutS, stderrS;
665
                FILE* stream;
666
                stream = fopen("/dev/null", "a+");
667
                d = fileno(stream);
668

    
669
                // create backup descriptors for the current stdout and stderr devices
670
                stdoutS = dup(STDOUT_FILENO);
671
                stderrS = dup(STDERR_FILENO);
672
                
673
                // redirect child output to /dev/null
674
                dup2(d, STDOUT_FILENO);
675
                //dup2(d, STDERR_FILENO);
676

    
677
                int pid = fork();
678
                if(pid == 0)
679
                {
680
                        execv(argv0, parameters_vector);
681
                        printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
682
                        exit(2);
683
                }
684
                else {
685
                        channel->StreamerProcess = pid;
686
                }
687

    
688
                // restore backup descriptors in the parent process
689
                dup2(stdoutS, STDOUT_FILENO);
690
                dup2(stderrS, STDERR_FILENO);
691

    
692
                fclose(stream);
693
                for(i=1; i<par_count; i++)
694
                        free(parameters_vector[i]);
695

    
696
#else
697
                STARTUPINFO sti;
698
                SECURITY_ATTRIBUTES sats = { 0 };
699
                int ret = 0;
700

    
701
                //set SECURITY_ATTRIBUTES struct fields
702
                sats.nLength = sizeof(sats);
703
                sats.bInheritHandle = TRUE;
704
                sats.lpSecurityDescriptor = NULL;
705

    
706
                ZeroMemory( &sti, sizeof(sti) );
707
                sti.cb = sizeof(sti);
708
                ZeroMemory( &channel->StreamerProcess, sizeof(PROCESS_INFORMATION) );
709

    
710
                char buffer[512];
711
                sprintf(buffer, "%s %s", argv0, parameters_string);
712

    
713
                if(!CreateProcess(NULL,
714
                  buffer,
715
                  &sats,
716
                  &sats,
717
                  TRUE,
718
                  0,
719
                  NULL,
720
                  NULL,
721
                  &sti,
722
                &channel->StreamerProcess))
723
                {
724
                        printf("Unable to generate process \n");
725
                        return -1;
726
                }
727
#endif
728
        }
729

    
730
        return 1;
731
}
732

    
733
int SwitchChannel(SChannel* channel)
734
{
735
        int i=0;
736
#ifdef RESTORE_SCREEN_ON_ZAPPING
737
        int was_fullscreen = FullscreenMode;
738
        int old_width = window_width, old_height = window_height;
739
#endif
740
        
741
        if(ChunkerPlayerCore_IsRunning())
742
                ChunkerPlayerCore_Stop();
743

    
744
#ifdef PSNR_PUBLICATION
745
        remove("NetworkID");
746
#endif
747
        
748
        ChunkerPlayerGUI_SetChannelRatio(channel->Ratio);
749
        ChunkerPlayerGUI_SetChannelTitle(channel->Title);
750
        ChunkerPlayerGUI_ForceResize(channel->Width, channel->Height);
751

    
752
        if (!scale_with_sdl) {        //TODO: maybe move to GUI
753
                int w=0, h=0;
754
                ChunkerPlayerGUI_AspectRatioResize((float)channel->Ratio, channel->Width, channel->Height, &w, &h);
755
                ChunkerPlayerCore_SetupOverlay(w, h);
756
        } else {
757
                ChunkerPlayerCore_SetupOverlay(channel->Width, channel->Height);
758
        }
759
        
760
        if(ChunkerPlayerCore_InitCodecs(channel->VideoCodec, channel->Width, channel->Height, channel->AudioCodec, channel->SampleRate, channel->AudioChannels) < 0)
761
        {
762
                printf("ERROR, COULD NOT INITIALIZE CODECS\n");
763
                exit(2);
764
        }
765
        
766
        //reset quality info
767
        channel->startTime = time(NULL);
768
        channel->instant_score = 0.0;
769
        channel->average_score = 0.0;
770
        channel->history_index = 0;
771
        for(i=0; i<CHANNEL_SCORE_HISTORY_SIZE; i++)
772
                channel->score_history[i] = -1;
773
        sprintf(channel->quality, "EVALUATING...");
774

    
775
        StartStreamer(channel);
776

    
777
#ifdef RESTORE_SCREEN_ON_ZAPPING
778
        if(SilentMode == 0) {
779
                if(was_fullscreen)
780
                        ChunkerPlayerGUI_ToggleFullscreen();
781
                else
782
                {
783
                        ChunkerPlayerGUI_HandleResize(old_width, old_height);
784
                }
785
        }
786
#endif
787

    
788
#ifdef PSNR_PUBLICATION
789
        if(RepoAddress[0]!='\0')        // TODO: search for RepoAddress currently disabled on linux
790
        {
791
            // Open Repository
792
            if(repoclient)
793
                    repClose(repoclient);
794
            repoclient=NULL;
795

    
796
            repoclient = repOpen(RepoAddress,0);
797
            if (repoclient == NULL)
798
                    printf("Unable to initialize PSNR publication in repoclient %s\n", RepoAddress);
799
    }
800
    else {
801
            printf("Repository address not present in streames launch string. Publication disabled\n");
802
    }
803
#endif
804

    
805

    
806
#ifdef PSNR_PUBLICATION
807
        // Read the Network ID
808
        int Error=true;
809
        char Line1[255], Line2[255];
810
        while(Error)
811
        {
812
            FILE* fp=fopen("NetworkID","r");        //TODO: better error handling needed, this could block the player if there are no write permissions
813
            if(fp)
814
            {
815
                if(ReadALine(fp,Line1,255)!=-1)
816
                    if(ReadALine(fp,Line2,255)!=-1)
817
                    {
818
                        if(strcmp(Line2,"IDEnd")==0)
819
                        {
820
                            strcpy(NetworkID,Line1);
821
                            Error=false;
822
                        }
823
                    }
824
                fclose(fp);
825
            }
826
            if(Error) usleep(100000);
827
        }
828
        
829
        printf("NetworkID = %s\n",NetworkID);
830
#endif
831
        
832
        ChunkerPlayerCore_Play();
833
        ChunkerPlayerGUI_ChannelSwitched();
834
        return 0;
835
}
836

    
837
void ZapDown()
838
{
839
        KILL_PROCESS(&Channels[SelectedChannel].StreamerProcess);
840
        SelectedChannel = ((SelectedChannel+1) %NChannels);
841
        SwitchChannel(&(Channels[SelectedChannel]));
842
}
843

    
844
void ZapUp()
845
{
846
        KILL_PROCESS(&Channels[SelectedChannel].StreamerProcess);
847
        SelectedChannel--;
848
        if(SelectedChannel < 0)
849
                SelectedChannel = NChannels-1;
850

    
851
        SwitchChannel(&(Channels[SelectedChannel]));
852
}
853

    
854
int enqueueBlock(const uint8_t *block, const int block_size)
855
{
856
        return ChunkerPlayerCore_EnqueueBlocks(block, block_size);
857
}