Revision e11386c0 chunker_player/chunker_player.c

View differences:

chunker_player/chunker_player.c
8 8
#include "player_defines.h"
9 9
#include "chunker_player.h"
10 10
#include "player_gui.h"
11
#include <time.h>
12
#include <getopt.h>
13

  
14
#define MANDATORY_PARAMS 3
15
#define OPTIONAL_PARAMS 1
16

  
17
#ifdef WIN32
18
#include <windows.h>
19
#endif
20

  
21
void sigproc()
22
{
23
	printf("you have pressed ctrl-c, terminating...\n");
24
	quit = 1;
25
}
26

  
27
static void print_usage(int argc, char *argv[])
28
{
29
  fprintf (stderr,
30
    "\nUsage:%s [options]\n"
31
    "\n"
32
    "Mandatory options:\n"
33
    "\t[-q q_thresh]: playout queue size\n"
34
    "\t[-c ChannelName]: channel name (from channels.conf)\n"
35
    "\t[-p port]: player http port\n\n"
36
    "Other options:\n"
37
    "\t[-t]: log traces (WARNING: old traces will be deleted).\n"
38
    "\t[-s mode]: silent mode (mode=1 no user gui and no audio, mode=2 audio only, mode=3 only gui and no P2P).\n\n"
39
    "=======================================================\n", argv[0]
40
    );
41
}
11 42

  
12 43
int main(int argc, char *argv[])
13 44
{
45
	srand ( time(NULL) );
14 46
	// some initializations
15 47
	SilentMode = 0;
16 48
	queue_filling_threshold = 0;
17
	SaveYUV = 0;
18 49
	quit = 0;
19 50
	QueueFillingMode=1;
20
	P2PProcessID = -1;
51
	LogTraces = 0;
52

  
53
#ifndef __WIN32__
54
	static pid_t fork_pid = -1;
55
	P2PProcessHandle=&fork_pid;
56
#else
57
	static PROCESS_INFORMATION ProcessInfo;
58
	ZeroMemory( &ProcessInfo, sizeof(ProcessInfo) );
59
	P2PProcessHandle=&ProcessInfo;
60
#endif
61

  
21 62
	NChannels = 0;
22 63
	SelectedChannel = -1;
23 64
	char firstChannelName[255];
......
25 66
	
26 67
	memset((void*)Channels, 0, (MAX_CHANNELS_NUM*sizeof(SChannel)));
27 68

  
69
#ifdef HTTPIO
28 70
	HttpPort = -1;
71
#endif
72
#ifdef TCPIO
73
	TcpPort = -1;
74
#endif
29 75
	struct MHD_Daemon *daemon = NULL;
30 76
	SDL_Event event;
31 77
	OverlayMutex = SDL_CreateMutex();
32

  
33
	FILE *fp;
34
		
35
	if(argc<6) {
36
		printf("chunker_player queue_thresh httpd_port silentMode LossTracesFilenameSuffix ChannelName <YUVFilename>\n");
37
		exit(1);
38
	}
39
	sscanf(argv[1],"%d",&queue_filling_threshold);
40
	sscanf(argv[2],"%d",&HttpPort);
41
	sscanf(argv[3],"%d",&SilentMode);
42
	sscanf(argv[4],"%s",LossTracesFilename);
43
	sscanf(argv[5],"%s",firstChannelName);
78
	int mandatories = 0;
44 79
	
45
	if(argc==7)
80
	char c;
81
	while ((c = getopt (argc, argv, "q:c:p:s:t")) != -1)
46 82
	{
47
		sscanf(argv[6],"%s",YUVFileName);
48
		printf("YUVFile: %s\n",YUVFileName);
49
		fp=fopen(YUVFileName, "wb");
50
		if(fp)
51
		{
52
			SaveYUV=1;
53
			fclose(fp);
83
		switch (c) {
84
			case 0: //for long options
85
				break;
86
			case 'q':
87
				sscanf(optarg, "%d", &queue_filling_threshold);
88
				mandatories++;
89
				break;
90
			case 'c':
91
				sprintf(firstChannelName, "%s", optarg);
92
				mandatories++;
93
				break;
94
			case 'p':
95
#ifdef HTTPIO
96
				sscanf(optarg, "%d", &HttpPort);
97
#endif
98
#ifdef TCPIO
99
				sscanf(optarg, "%d", &TcpPort);
100
#endif
101
				mandatories++;
102
				break;
103
			case 's':
104
				sscanf(optarg, "%d", &SilentMode);
105
				break;
106
			case 't':
107
				DELETE_DIR("traces");
108
				CREATE_DIR("traces");
109
				LogTraces = 1;
110
				break;
111
			default:
112
				print_usage(argc, argv);
113
				return -1;
54 114
		}
55
		else
56
			printf("ERROR: Unable to create YUVFile\n");
57 115
	}
58
	
59
	char filename[255];
60
	sprintf(filename, "audio_%s", LossTracesFilename);
61
	fp=fopen(filename, "wb");
62
	if(fp)
116
	if(mandatories < MANDATORY_PARAMS)
63 117
	{
64
		fclose(fp);
65
		sprintf(filename, "video_%s", LossTracesFilename);
66
		fp=fopen(filename, "wb");
67
		if(fp)
68
			fclose(fp);
69
		else
70
		{
71
			printf("ERROR: Unable to create loss trace files\n");
72
			exit(1);
73
		}
118
		print_usage(argc, argv);
119
		return -1;
74 120
	}
75
	else
121

  
122
#ifdef EMULATE_CHUNK_LOSS
123
	ScheduledChunkLosses = NULL;
124
	cfg_opt_t scheduled_chunk_loss_opts[] =
76 125
	{
77
		printf("ERROR: Unable to create loss trace files\n");
78
		exit(1);
126
		CFG_INT("Time", 0, CFGF_NONE),
127
		CFG_INT("Value", 0, CFGF_NONE),
128
		CFG_INT("MinValue", 0, CFGF_NONE),
129
		CFG_INT("MaxValue", 0, CFGF_NONE),
130
		CFG_INT("Burstiness", 0, CFGF_NONE),
131
		CFG_END()
132
	};
133
	cfg_opt_t opts[] =
134
	{
135
		CFG_SEC("ScheduledChunkLoss", scheduled_chunk_loss_opts, CFGF_MULTI),
136
		CFG_END()
137
	};
138
	cfg_t *cfg, *cfg_sched;
139
	cfg = cfg_init(opts, CFGF_NONE);
140
	if(!cfg_parse(cfg, "_chunklossrate.conf") == CFG_PARSE_ERROR)
141
	{
142
		NScheduledChunkLosses = cfg_size(cfg, "ScheduledChunkLoss");
143
		if(NScheduledChunkLosses > 0)
144
			ScheduledChunkLosses = (SChunkLoss*)malloc((NScheduledChunkLosses)*sizeof(SChunkLoss));
145
		
146
		int j;
147
		for(j = 0; j < cfg_size(cfg, "ScheduledChunkLoss"); j++)
148
		{
149
			cfg_sched = cfg_getnsec(cfg, "ScheduledChunkLoss", j);
150
			ScheduledChunkLosses[j].Time = cfg_getint(cfg_sched, "Time");
151
			ScheduledChunkLosses[j].Value = cfg_getint(cfg_sched, "Value");
152
			ScheduledChunkLosses[j].Burstiness = cfg_getint(cfg_sched, "Burstiness");
153
			
154
			// -1 means random value between min and max
155
			if(ScheduledChunkLosses[j].Value == -1)
156
			{
157
				ScheduledChunkLosses[j].MinValue = cfg_getint(cfg_sched, "MinValue");
158
				ScheduledChunkLosses[j].MaxValue = cfg_getint(cfg_sched, "MaxValue");
159
			}
160
		}
161
		cfg_free(cfg);
162
		CurrChunkLossIndex = -1;
163
		
164
		for(j=0; j < NScheduledChunkLosses; j++)
165
		{
166
			printf("ScheduledChunkLosses[%d].Time = %ld\n", j, ScheduledChunkLosses[j].Time);
167
			printf("ScheduledChunkLosses[%d].Value = %d\n", j, ScheduledChunkLosses[j].Value);
168
			printf("ScheduledChunkLosses[%d].Burstiness = %d\n", j, ScheduledChunkLosses[j].Burstiness);
169
		}
79 170
	}
171
#endif
80 172

  
173
#ifdef HTTPIO
81 174
	//this thread fetches chunks from the network by listening to the following path, port
82 175
	daemon = (struct MHD_Daemon*)initChunkPuller(UL_DEFAULT_EXTERNALPLAYER_PATH, HttpPort);
83 176
	if(daemon == NULL)
84 177
	{
85 178
		printf("CANNOT START MICROHTTPD SERVICE, EXITING...\n");
86
//		KILLALL("offerstreamer");
87 179
		exit(2);
88 180
	}
181
#endif
182
#ifdef TCPIO
183
	int fd = initChunkPuller(TcpPort);
184
	if(! (fd > 0))
185
	{
186
		printf("CANNOT START TCP PULLER...\n");
187
		exit(2);
188
	}
189
#endif
89 190

  
90 191
	if(!SilentMode)
91 192
	{
......
121 222
	
122 223
	if(firstChannelIndex < 0)
123 224
	{
124
		printf("Cannot find the specified channel (%s) into the configuration file (channels.conf), exiting\n");
225
		printf("Cannot find the specified channel (%s) into the configuration file (channels.conf), exiting\n", firstChannelName);
125 226
		exit(0);
126 227
	}
127 228
	
......
218 319
		}
219 320
		usleep(120000);
220 321
	}
221
	
222
	if(P2PProcessID > 0)
223
		KILL_PROCESS(P2PProcessID);
322

  
323
	KILL_PROCESS(P2PProcessHandle);
224 324

  
225 325
	//TERMINATE
226 326
	ChunkerPlayerCore_Stop();
......
230 330
	ChunkerPlayerGUI_Close();
231 331
	SDL_DestroyMutex(OverlayMutex);
232 332
	SDL_Quit();
333
	
334
#ifdef HTTPIO
233 335
	finalizeChunkPuller(daemon);
336
#endif
337
#ifdef TCPIO
338
	finalizeChunkPuller();
339
#endif
340
	
341
#ifdef EMULATE_CHUNK_LOSS
342
	if(ScheduledChunkLosses)
343
		free(ScheduledChunkLosses);
344
#endif
234 345
	return 0;
235 346
}
236 347

  
348
int cb_validate_conffile(cfg_t *cfg)
349
{
350
	char LaunchString[255];
351
	cfg_t *cfg_greet;
352
	
353
	if(cfg_size(cfg, "Channel") == 0)
354
	{
355
		cfg_error(cfg, "no \"Channel\" section found");
356
		return -1;
357
	}
358
	
359
	printf("\t%d Channel setions found\n", cfg_size(cfg, "Channel"));
360
	
361
	int j;
362
	for(j = 0; j < cfg_size(cfg, "Channel"); j++)
363
	{
364
		cfg_greet = cfg_getnsec(cfg, "Channel", j);
365
		sprintf(LaunchString, "%s", cfg_getstr(cfg_greet, "LaunchString"));
366
		if(!(strlen(LaunchString) > 0))
367
		{
368
			cfg_error(cfg, "invalid LaunchString for Channel[%d]", j);
369
			return -1;
370
		}
371
		printf("\tChannel[%d].LaunchString = %s\n", j, LaunchString);
372
		printf("\tChannel[%d].AudioChannels = %ld\n", j, cfg_getint(cfg_greet, "AudioChannels"));
373
		printf("\tChannel[%d].SampleRate = %ld\n", j, cfg_getint(cfg_greet, "SampleRate"));
374
		printf("\tChannel[%d].Width = %ld\n", j, cfg_getint(cfg_greet, "Width"));
375
		printf("\tChannel[%d].Height = %ld\n", j, cfg_getint(cfg_greet, "Height"));
376
		printf("\tChannel[%d].Bitrate = %ld\n", j, cfg_getint(cfg_greet, "Bitrate"));
377
		printf("\tChannel[%d].Ratio = %s\n", j, cfg_getstr(cfg_greet, "Ratio"));
378
	}
379
    return 0;
380
}
381

  
237 382
int ParseConf()
238 383
{
239 384
	int j;
......
247 392
		CFG_INT("SampleRate", 48000, CFGF_NONE),
248 393
		CFG_INT("Width", 176, CFGF_NONE),
249 394
		CFG_INT("Height", 144, CFGF_NONE),
250
		CFG_FLOAT("Ratio", 1.22, CFGF_NONE),
395
		CFG_INT("Bitrate", 0, CFGF_NONE),
396
		
397
		// for some reason libconfuse parsing for floating point does not work in windows
398
		//~ CFG_FLOAT("Ratio", 1.22, CFGF_NONE),
399
		CFG_STR("Ratio", "1.22", CFGF_NONE),
251 400
		CFG_END()
252 401
	};
253 402
	cfg_opt_t opts[] =
254 403
	{
255
		CFG_STR("PeerExecName", DEFAULT_CHANNEL_EXEC_NAME, CFGF_NONE),
256 404
		CFG_SEC("Channel", channel_opts, CFGF_TITLE | CFGF_MULTI),
257 405
		CFG_END()
258 406
	};
......
261 409
	if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_PARSE_ERROR)
262 410
	{
263 411
		printf("Error while parsing configuration file, exiting...\n");
412
		cb_validate_conffile(cfg);
264 413
		return 1;
265 414
	}
266 415
	
......
270 419
		return 1;
271 420
	}
272 421
	
273
	sprintf(OfferStreamerFilename, "%s", cfg_getstr(cfg, "PeerExecName"));
274
	
275 422
	FILE * tmp_file;
276
	if(tmp_file = fopen(OfferStreamerFilename, "r"))
423
	if(tmp_file = fopen(DEFAULT_PEEREXECNAME_FILENAME, "r")) {
424
		if(fscanf(tmp_file, "%s", StreamerFilename) != 1) {
425
			printf("Wrong format of conf file %s containing peer application exec name. Assuming default: %s.\n\n", DEFAULT_PEEREXECNAME_FILENAME, DEFAULT_PEER_EXEC_NAME);
426
		}
427
		fclose(tmp_file);
428
	}
429
	else {
430
		printf("Could not find conf file %s containing peer application exec name. Exiting.\n\n", DEFAULT_PEEREXECNAME_FILENAME);
431
		exit(1);
432
	}
433
	if(tmp_file = fopen(StreamerFilename, "r"))
277 434
    {
278 435
        fclose(tmp_file);
279 436
    }
280 437
    else
281 438
	{
282
		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", OfferStreamerFilename);
439
		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);
283 440
		exit(1);
284 441
	}
285 442
	
......
292 449
		Channels[j].Height = cfg_getint(cfg_channel, "Height");
293 450
		Channels[j].AudioChannels = cfg_getint(cfg_channel, "AudioChannels");
294 451
		Channels[j].SampleRate = cfg_getint(cfg_channel, "SampleRate");
295
		Channels[j].Ratio = cfg_getfloat(cfg_channel, "Ratio");
452
		Channels[j].Ratio = strtof(cfg_getstr(cfg_channel, "Ratio"), 0);
453
		Channels[j].Bitrate = cfg_getint(cfg_channel, "Bitrate");
454
		
296 455
		Channels[j].Index = j+1;
297 456
		NChannels++;
298 457
	}
......
301 460
	return 0;
302 461
}
303 462

  
463
int ReTune(SChannel* channel)
464
{	
465
	if(ChunkerPlayerCore_IsRunning())
466
		ChunkerPlayerCore_Pause();
467
	
468
	//reset quality info
469
	channel->startTime = time(NULL);
470
	
471
	ChunkerPlayerCore_Play();
472
	
473
	return 0;
474
}
475

  
304 476
int SwitchChannel(SChannel* channel)
305 477
{
306 478
	int i=0;
......
312 484
	if(ChunkerPlayerCore_IsRunning())
313 485
		ChunkerPlayerCore_Stop();
314 486

  
315
	if(P2PProcessID > 0)
316
		KILL_PROCESS(P2PProcessID);
487
	KILL_PROCESS(P2PProcessHandle);
317 488
	
318 489
	ratio = channel->Ratio;
319 490
	ChunkerPlayerGUI_SetChannelTitle(channel->Title);
320 491
	ChunkerPlayerGUI_ForceResize(channel->Width, channel->Height);
321 492
	
322
	ChunkerPlayerCore_SetupOverlay(channel->Width, channel->Height);
493
	int w=0, h=0;
494
	ChunkerPlayerGUI_AspectRatioResize((float)channel->Ratio, channel->Width, channel->Height, &w, &h);
495
	ChunkerPlayerCore_SetupOverlay(w, h);
323 496
	//ChunkerPlayerGUI_SetupOverlayRect(channel);
324 497
	
325
	ChunkerPlayerCore_InitCodecs(channel->Width, channel->Height, channel->SampleRate, channel->AudioChannels);
326
		
327
	char* parameters_vector[255];
328
	char argv0[255], parameters_string[511];
329
	sprintf(argv0, "%s", OfferStreamerFilename);
330
	
331
	sprintf(parameters_string, "%s %s %s %s %s %d %s %d", argv0, channel->LaunchString, "-C", channel->Title, "-P", (HttpPort+channel->Index), "-F", HttpPort);
332
	
333
	printf("EXECUTING %s\n", parameters_string);
334
	
335
	int par_count=0;
336
	
337
	// split parameters and count them
338
	char* pch = strtok (parameters_string, " ");
339
	
340
	while (pch != NULL)
498
	if(ChunkerPlayerCore_InitCodecs(channel->Width, channel->Height, channel->SampleRate, channel->AudioChannels) < 0)
341 499
	{
342
		if(par_count > 255) break;
343
		// printf ("\tpch=%s\n",pch);
344
		parameters_vector[par_count] = (char*) malloc(sizeof(char)*(strlen(pch)+1));
345
		strcpy(parameters_vector[par_count], pch);
346
		pch = strtok (NULL, " ");
347
		par_count++;
500
		printf("ERROR, COULD NOT INITIALIZE CODECS\n");
501
		exit(2);
348 502
	}
349
	parameters_vector[par_count] = NULL;
350

  
503
	
351 504
	//reset quality info
352 505
	channel->startTime = time(NULL);
353 506
	channel->instant_score = 0.0;
......
356 509
	for(i=0; i<CHANNEL_SCORE_HISTORY_SIZE; i++)
357 510
		channel->score_history[i] = -1;
358 511
	sprintf(channel->quality, "EVALUATING...");
512
	
513
	if(SilentMode != 3) //mode 3 is for GUI only, no P2P peer process
514
	{
515
		char argv0[255], parameters_string[511];
516
		sprintf(argv0, "%s", StreamerFilename);
359 517

  
360
#ifdef __LINUX__
518
#ifdef HTTPIO
519
		sprintf(parameters_string, "%s %s %s %d %s %s %d", "-C", channel->Title, "-P", (HttpPort+channel->Index), channel->LaunchString, "-F", HttpPort);
520
#endif
361 521

  
362
	int d;
363
	int stdoutS, stderrS;
364
	FILE* stream;
365
	stream = fopen("/dev/null", "a+");
366
	d = fileno(stream);
522
#ifdef TCPIO
523
		sprintf(parameters_string, "%s %s %s %d %s %s 127.0.0.1:%d", "-C", channel->Title, "-P", (TcpPort+channel->Index), channel->LaunchString, "-F", TcpPort);
524
#endif
367 525

  
368
	// create backup descriptors for the current stdout and stderr devices
369
	stdoutS = dup(STDOUT_FILENO);
370
	stderrS = dup(STDERR_FILENO);
371
	
372
	// redirect child output to /dev/null
373
	dup2(d, STDOUT_FILENO);
374
	dup2(d, STDERR_FILENO);
526
		printf("OFFERSTREAMER LAUNCH STRING: %s %s\n", argv0, parameters_string);
375 527

  
376
	int pid = fork();
377
	if(pid == 0)
378
	{
379
		execv(argv0, parameters_vector);
380
		printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
381
		exit(2);
382
	}
383
	else
384
		P2PProcessID = pid;
385
	
386
	// restore backup descriptors in the parent process
387
	dup2(stdoutS, STDOUT_FILENO);
388
	dup2(stderrS, STDERR_FILENO);
389
	
390
	for(i=0; i<par_count; i++)
391
		free(parameters_vector[i]);
528
#ifndef __WIN32__
529
		char* parameters_vector[255];
530
		parameters_vector[0] = argv0;
531
		
532
		// split parameters and count them
533
		int par_count=1;
534
		char* pch = strtok (parameters_string, " ");
535
		while (pch != NULL)
536
		{
537
			if(par_count > 255) break;
538
			// printf ("\tpch=%s\n",pch);
539
			parameters_vector[par_count] = (char*) malloc(sizeof(char)*(strlen(pch)+1));
540
			strcpy(parameters_vector[par_count], pch);
541
			pch = strtok (NULL, " ");
542
			par_count++;
543
		}
544
		parameters_vector[par_count] = NULL;
545

  
546
		int d;
547
		int stdoutS, stderrS;
548
		FILE* stream;
549
		stream = fopen("/dev/null", "a+");
550
		d = fileno(stream);
551

  
552
		// create backup descriptors for the current stdout and stderr devices
553
		stdoutS = dup(STDOUT_FILENO);
554
		stderrS = dup(STDERR_FILENO);
392 555
		
393
	fclose(stream);
556
		// redirect child output to /dev/null
557
		dup2(d, STDOUT_FILENO);
558
		dup2(d, STDERR_FILENO);
559

  
560
		int pid = fork();
561
		if(pid == 0)
562
		{
563
			execv(argv0, parameters_vector);
564
			printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
565
			exit(2);
566
		}
567
		else
568
			*((pid_t*)P2PProcessHandle) = pid;
569
		
570
		// restore backup descriptors in the parent process
571
		dup2(stdoutS, STDOUT_FILENO);
572
		dup2(stderrS, STDERR_FILENO);
573
		
574
		for(i=1; i<par_count; i++)
575
			free(parameters_vector[i]);
576
			
577
		fclose(stream);
394 578

  
395 579
#ifdef RESTORE_SCREEN_ON_ZAPPING
396
	if(was_fullscreen)
397
		ChunkerPlayerGUI_ToggleFullscreen();
398
	else
399
	{
400
		ChunkerPlayerGUI_HandleResize(old_width, old_height);
401
	}
580
		if(was_fullscreen)
581
			ChunkerPlayerGUI_ToggleFullscreen();
582
		else
583
		{
584
			ChunkerPlayerGUI_HandleResize(old_width, old_height);
585
		}
402 586
#endif
403 587
	
404
	ChunkerPlayerCore_Play();
405
	
406
	return 0;
588
#else
589

  
590
		STARTUPINFO sti;
591
		SECURITY_ATTRIBUTES sats = { 0 };
592
		DWORD writ, excode, read, available;
593
		int ret = 0;
594

  
595
		//set SECURITY_ATTRIBUTES struct fields
596
		sats.nLength = sizeof(sats);
597
		sats.bInheritHandle = TRUE;
598
		sats.lpSecurityDescriptor = NULL;
599

  
600
		ZeroMemory( &sti, sizeof(sti) );
601
		sti.cb = sizeof(sti);
602
		ZeroMemory( P2PProcessHandle, sizeof(PROCESS_INFORMATION) );
603

  
604
		char buffer[512];
605
		sprintf(buffer, "%s %s", argv0, parameters_string);
606

  
607
		if(!CreateProcess(NULL,
608
	  	buffer,
609
	  	&sats,
610
	  	&sats,
611
	  	TRUE,
612
	  	0,
613
	  	NULL,
614
	  	NULL,
615
	  	&sti,
616
	  	P2PProcessHandle))
617
		{
618
			printf("Unable to generate process \n");
619
			return -1;
620
		}
407 621
#endif
408 622

  
409
	return 1;
623
	}
624
	ChunkerPlayerCore_Play();
625
	ChunkerPlayerGUI_ChannelSwitched();
626
	return 0;
410 627
}
411 628

  
412 629
void ZapDown()

Also available in: Unified diff