xref: /haiku/src/add-ons/media/media-add-ons/dvb/DVBMediaNode.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
1 /*
2  * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify,
8  * merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 
26 #include <fcntl.h>
27 #include <malloc.h>
28 #include <math.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/uio.h>
33 #include <unistd.h>
34 
35 #include <MediaRoster.h>
36 #include <Buffer.h>
37 #include <BufferGroup.h>
38 #include <ParameterWeb.h>
39 #include <TimeSource.h>
40 #include <String.h>
41 #include <Autolock.h>
42 #include <Debug.h>
43 
44 #include <Directory.h>
45 #include <Entry.h>
46 #include <Path.h>
47 
48 #include "MediaFormat.h"
49 #include "Packet.h"
50 #include "PacketQueue.h"
51 #include "pes.h"
52 #include "config.h"
53 
54 //#define DUMP_VIDEO
55 //#define DUMP_AUDIO
56 //#define DUMP_RAW_AUDIO
57 //#define DUMP_MPEG_TS
58 
59 
60 #include "DVBMediaNode.h"
61 
62 #define ENABLE_TRACE
63 //#define ENABLE_TRACE_TIMING
64 
65 #undef TRACE
66 
67 #ifdef ENABLE_TRACE
68 	#define TRACE printf
69 #else
70 	#define TRACE(a...)
71 #endif
72 
73 #ifdef ENABLE_TRACE_TIMING
74 	#define TRACE_TIMING printf
75 #else
76 	#define TRACE_TIMING(a...)
77 #endif
78 
79 #define RETURN_IF_ERROR(expr) { status_t e = (expr); if (e != B_OK) return e; }
80 
81 #define ID_RAW_VIDEO	0
82 #define ID_RAW_AUDIO	1
83 #define ID_ENC_VIDEO	2
84 #define ID_ENC_AUDIO	3
85 #define ID_TS			4
86 
87 // Timeouts for requesting buffers, if the system is busy,
88 // the output buffer queue is full, requesting a buffer will
89 // timeout, and we need to drop the current data
90 #define VIDEO_BUFFER_REQUEST_TIMEOUT	20000
91 #define AUDIO_BUFFER_REQUEST_TIMEOUT	10000
92 
93 // DVB data arrives early and with a timestamp, this is used to validate
94 // that the timestamp is correct and we don't get stuck
95 #define VIDEO_MAX_EARLY					3000000
96 	// up to 3 seconds too early
97 #define VIDEO_MAX_LATE					50000
98 	// no more than 50 ms too late
99 #define AUDIO_MAX_EARLY					3000000
100 	// up to 3 seconds too early
101 #define AUDIO_MAX_LATE					50000
102 	// no more than 50 ms too late
103 
104 #define PROCESSING_LATENCY				1500
105 	// assumed latency for sending the buffer
106 
107 #define STOP_CAPTURE_WHILE_TUNING		1
108 
109 #define M_REFRESH_PARAMETER_WEB 		(BTimedEventQueue::B_USER_EVENT + 1)
110 
111 
112 DVBMediaNode::DVBMediaNode(
113 	BMediaAddOn *addon, const char *name,
114 	int32 internal_id, DVBCard *card)
115  :	BMediaNode(name)
116  ,	BBufferProducer(B_MEDIA_RAW_VIDEO)
117  ,	BControllable()
118  ,	BMediaEventLooper()
119  ,	fStopDisabled(false)
120  ,	fOutputEnabledRawVideo(false)
121  ,	fOutputEnabledRawAudio(false)
122  ,	fOutputEnabledEncVideo(false)
123  ,	fOutputEnabledEncAudio(false)
124  ,	fOutputEnabledTS(false)
125  ,	fCardDataQueue(new PacketQueue(6))
126  ,	fRawVideoQueue(new PacketQueue(56))
127  ,	fRawAudioQueue(new PacketQueue(56))
128  ,	fEncVideoQueue(new PacketQueue(56))
129  ,	fEncAudioQueue(new PacketQueue(56))
130  ,	fMpegTsQueue(new PacketQueue(16))
131  ,	fCard(card)
132  ,	fCaptureThreadsActive(false)
133  ,	fThreadIdCardReader(-1)
134  ,	fThreadIdMpegDemux(-1)
135  ,	fThreadIdRawAudio(-1)
136  ,	fThreadIdRawVideo(-1)
137  ,	fThreadIdEncAudio(-1)
138  ,	fThreadIdEncVideo(-1)
139  ,	fThreadIdMpegTS(-1)
140  ,	fTerminateThreads(false)
141  ,	fDemux(new TransportStreamDemux(fRawVideoQueue, fRawAudioQueue,
142  		fEncVideoQueue, fEncAudioQueue, fMpegTsQueue))
143  ,	fBufferGroupRawVideo(0)
144  ,	fBufferGroupRawAudio(0)
145  ,	fInterfaceType(DVB_TYPE_UNKNOWN)
146  ,	fAudioPid(-1)
147  ,	fVideoPid(-1)
148  ,	fPcrPid(-1)
149  ,	fTuningSuccess(false)
150  ,	fCaptureActive(false)
151  ,	fVideoDelaySem(create_sem(0, "video delay sem"))
152  ,	fAudioDelaySem(create_sem(0, "audio delay sem"))
153  ,	fSelectedState(-1)
154  ,	fSelectedRegion(-1)
155  ,	fSelectedChannel(-1)
156  ,	fSelectedAudio(-1)
157  ,	fStateList(new StringList)
158  ,	fRegionList(new StringList)
159  ,	fChannelList(new StringList)
160  ,	fAudioList(new StringList)
161  ,	fVideoDecoder(0)
162  ,	fAudioDecoder(0)
163  ,	fCurrentVideoPacket(0)
164  ,	fCurrentAudioPacket(0)
165 {
166 	TRACE("DVBMediaNode::DVBMediaNode\n");
167 
168 	AddNodeKind(B_PHYSICAL_INPUT);
169 
170 	fInternalID = internal_id;
171 	fAddOn = addon;
172 
173 	fInitStatus = B_OK;
174 
175 	InitDefaultFormats();
176 
177 	// in the beginning, the required formats are the same as the defaults
178 	fRequiredFormatRawVideo = fDefaultFormatRawVideo;
179 	fRequiredFormatRawAudio = fDefaultFormatRawAudio;
180 	fRequiredFormatEncVideo = fDefaultFormatEncVideo;
181 	fRequiredFormatEncAudio = fDefaultFormatEncAudio;
182 	fRequiredFormatTS = fDefaultFormatTS;
183 
184 	TRACE("current RunMode = %d\n", RunMode());
185 
186 #ifdef DUMP_VIDEO
187 	fVideoFile = open("/boot/home/dvb-video.mpg", O_RDWR | O_CREAT | O_TRUNC);
188 #endif
189 #ifdef DUMP_AUDIO
190 	fAudioFile = open("/boot/home/dvb-audio.mpg", O_RDWR | O_CREAT | O_TRUNC);
191 #endif
192 #ifdef DUMP_RAW_AUDIO
193 	fRawAudioFile = open("/boot/home/dvb-audio.raw",
194 		O_RDWR | O_CREAT | O_TRUNC);
195 #endif
196 #ifdef DUMP_MPEG_TS
197 	fMpegTsFile = open("/boot/home/dvb-mpeg.ts", O_RDWR | O_CREAT | O_TRUNC);
198 #endif
199 }
200 
201 
202 DVBMediaNode::~DVBMediaNode()
203 {
204 	TRACE("DVBMediaNode::~DVBMediaNode\n");
205 
206 	StopCapture();
207 
208 	delete_sem(fVideoDelaySem);
209 	delete_sem(fAudioDelaySem);
210 
211 	// fCard is owned by the media addon
212 	delete fCardDataQueue;
213 	delete fRawVideoQueue;
214 	delete fRawAudioQueue;
215 	delete fEncVideoQueue;
216 	delete fEncAudioQueue;
217 	delete fMpegTsQueue;
218 
219 	delete fDemux;
220 
221 	delete fBufferGroupRawVideo;
222 	delete fBufferGroupRawAudio;
223 
224 	delete fStateList;
225 	delete fRegionList;
226 	delete fChannelList;
227 	delete fAudioList;
228 
229 #ifdef DUMP_VIDEO
230 	close(fVideoFile);
231 #endif
232 #ifdef DUMP_AUDIO
233 	close(fAudioFile);
234 #endif
235 #ifdef DUMP_RAW_AUDIO
236 	close(fRawAudioFile);
237 #endif
238 #ifdef DUMP_MPEG_TS
239 	close(fMpegTsFile);
240 #endif
241 
242 }
243 
244 
245 /* BMediaNode */
246 
247 
248 BMediaAddOn *
249 DVBMediaNode::AddOn(int32 *internal_id) const
250 {
251 	if (internal_id)
252 		*internal_id = fInternalID;
253 	return fAddOn;
254 }
255 
256 
257 status_t
258 DVBMediaNode::HandleMessage(int32 message, const void *data, size_t size)
259 {
260 	return B_ERROR;
261 }
262 
263 
264 void
265 DVBMediaNode::Preroll()
266 {
267 	/* This hook may be called before the node is started to give the hardware
268 	 * a chance to start. */
269 }
270 
271 
272 void
273 DVBMediaNode::SetTimeSource(BTimeSource *time_source)
274 {
275 	TRACE("DVBMediaNode::SetTimeSource\n");
276 	//printf("current RunMode = %d\n", RunMode());
277 	//printf("_m_recordDelay = %Ld\n", _m_recordDelay);
278 }
279 
280 
281 void
282 DVBMediaNode::SetRunMode(run_mode mode)
283 {
284 	TRACE("DVBMediaNode::SetRunMode: %d\n", mode);
285 	TRACE("current RunMode = %d\n", RunMode());
286 	//printf("_m_recordDelay = %Ld\n", _m_recordDelay);
287 }
288 
289 
290 /* BMediaEventLooper */
291 
292 
293 void
294 DVBMediaNode::NodeRegistered()
295 {
296 	TRACE("DVBMediaNode::NodeRegistered\n");
297 
298 	fOutputRawVideo.node = Node();
299 	fOutputRawVideo.source.port = ControlPort();
300 	fOutputRawVideo.source.id = ID_RAW_VIDEO;
301 	fOutputRawVideo.destination = media_destination::null;
302 	fOutputRawVideo.format = fDefaultFormatRawVideo;
303 	strcpy(fOutputRawVideo.name, SourceDefaultName(fOutputRawVideo.source));
304 
305 	fOutputRawAudio.node = Node();
306 	fOutputRawAudio.source.port = ControlPort();
307 	fOutputRawAudio.source.id = ID_RAW_AUDIO;
308 	fOutputRawAudio.destination = media_destination::null;
309 	fOutputRawAudio.format = fDefaultFormatRawAudio;
310 	strcpy(fOutputRawAudio.name, SourceDefaultName(fOutputRawAudio.source));
311 
312 	fOutputEncVideo.node = Node();
313 	fOutputEncVideo.source.port = ControlPort();
314 	fOutputEncVideo.source.id = ID_ENC_VIDEO;
315 	fOutputEncVideo.destination = media_destination::null;
316 	fOutputEncVideo.format = fDefaultFormatEncVideo;
317 	strcpy(fOutputEncVideo.name, SourceDefaultName(fOutputEncVideo.source));
318 
319 	fOutputEncAudio.node = Node();
320 	fOutputEncAudio.source.port = ControlPort();
321 	fOutputEncAudio.source.id = ID_ENC_AUDIO;
322 	fOutputEncAudio.destination = media_destination::null;
323 	fOutputEncAudio.format = fDefaultFormatEncAudio;
324 	strcpy(fOutputEncAudio.name, SourceDefaultName(fOutputEncAudio.source));
325 
326 	fOutputTS.node = Node();
327 	fOutputTS.source.port = ControlPort();
328 	fOutputTS.source.id = ID_TS;
329 	fOutputTS.destination = media_destination::null;
330 	fOutputTS.format = fDefaultFormatTS;
331 	strcpy(fOutputTS.name, SourceDefaultName(fOutputTS.source));
332 
333 	fCard->GetCardType(&fInterfaceType);
334 
335 	// set control thread priority
336 	SetPriority(110);
337 
338 	LoadSettings();
339 
340 	RefreshParameterWeb();
341 
342 	// this nodes operates in recording mode, so set it (will be done
343 	// asynchronously)
344 	BMediaRoster::Roster()->SetRunModeNode(Node(), B_RECORDING);
345 		// as it's a notification hook, calling this doesn't work:
346 		// SetRunMode(B_RECORDING);
347 
348 	//printf("RunMode = %d\n", RunMode());
349 	//printf("_m_recordDelay = %Ld\n", _m_recordDelay);
350 
351 	Run();
352 }
353 
354 
355 void
356 DVBMediaNode::Stop(bigtime_t performance_time, bool immediate)
357 {
358 	if (fStopDisabled)
359 		return;
360 	else
361 		BMediaEventLooper::Stop(performance_time, immediate);
362 }
363 
364 
365 void
366 DVBMediaNode::HandleEvent(const media_timed_event *event,
367 		bigtime_t lateness, bool realTimeEvent)
368 {
369 
370 	switch(event->type)
371 	{
372 		case M_REFRESH_PARAMETER_WEB:
373 			RefreshParameterWeb();
374 			break;
375 		case BTimedEventQueue::B_START:
376 			HandleStart(event->event_time);
377 			break;
378 		case BTimedEventQueue::B_STOP:
379 			HandleStop();
380 			break;
381 		case BTimedEventQueue::B_WARP:
382 			HandleTimeWarp(event->bigdata);
383 			break;
384 		case BTimedEventQueue::B_SEEK:
385 			HandleSeek(event->bigdata);
386 			break;
387 		case BTimedEventQueue::B_HANDLE_BUFFER:
388 		case BTimedEventQueue::B_DATA_STATUS:
389 		case BTimedEventQueue::B_PARAMETER:
390 		default:
391 			TRACE("DVBMediaNode::HandleEvent: Unhandled event -- %lx\n",
392 				event->type);
393 			break;
394 	}
395 }
396 
397 
398 /* BBufferProducer */
399 
400 
401 status_t
402 DVBMediaNode::FormatChangeRequested(const media_source &source,
403 		const media_destination &destination, media_format *io_format,
404 		int32 *_deprecated_)
405 {
406 	TRACE("DVBMediaNode::FormatChangeRequested denied: %s\n",
407 		SourceDefaultName(source));
408 	return B_ERROR;
409 }
410 
411 
412 status_t
413 DVBMediaNode::GetNextOutput(int32 *cookie, media_output *out_output)
414 {
415 	switch (*cookie) {
416 		case 0: *out_output = fOutputRawVideo;	break;
417 		case 1: *out_output = fOutputRawAudio;	break;
418 		case 2: *out_output = fOutputEncVideo;	break;
419 		case 3: *out_output = fOutputEncAudio;	break;
420 		case 4: *out_output = fOutputTS;		break;
421 		default:								return B_BAD_INDEX;
422 	}
423 
424 	(*cookie) += 1;
425 	return B_OK;
426 }
427 
428 
429 status_t
430 DVBMediaNode::DisposeOutputCookie(int32 cookie)
431 {
432 	return B_OK;
433 }
434 
435 
436 status_t
437 DVBMediaNode::SetBufferGroup(const media_source &source, BBufferGroup *group)
438 {
439 	TRACE("DVBMediaNode::SetBufferGroup denied: %s\n",
440 		SourceDefaultName(source));
441 	return B_ERROR;
442 }
443 
444 
445 status_t
446 DVBMediaNode::VideoClippingChanged(const media_source &for_source,
447 		int16 num_shorts, int16 *clip_data,
448 		const media_video_display_info &display, int32 *_deprecated_)
449 {
450 	return B_ERROR;
451 }
452 
453 
454 status_t
455 DVBMediaNode::GetLatency(bigtime_t *out_latency)
456 {
457 	if (B_OK != BBufferProducer::GetLatency(out_latency))
458 		*out_latency = 50000;
459 
460 	printf("DVBMediaNode::GetLatency: %Ld\n", *out_latency);
461 	*out_latency += PROCESSING_LATENCY;
462 	return B_OK;
463 }
464 
465 
466 status_t
467 DVBMediaNode::FormatSuggestionRequested(
468 		media_type type, int32 quality, media_format *format)
469 {
470 	TRACE("DVBMediaNode::FormatSuggestionRequested\n");
471 
472 	switch (type) {
473 		case B_MEDIA_RAW_VIDEO:
474 			*format = fDefaultFormatRawVideo;
475 			break;
476 
477 		case B_MEDIA_RAW_AUDIO:
478 			*format = fDefaultFormatRawAudio;
479 			break;
480 
481 		case B_MEDIA_ENCODED_VIDEO:
482 			*format = fDefaultFormatEncVideo;
483 			break;
484 
485 		case B_MEDIA_ENCODED_AUDIO:
486 			*format = fDefaultFormatEncAudio;
487 			break;
488 
489 		case B_MEDIA_MULTISTREAM:
490 			*format = fDefaultFormatTS;
491 			break;
492 
493 		default:
494 			TRACE("Bad type!\n");
495 			return B_MEDIA_BAD_FORMAT;
496 	}
497 
498 	#ifdef DEBUG
499 		TRACE("suggested format: ");
500 		PrintFormat(*format);
501 	#endif
502 
503 	return B_OK;
504 }
505 
506 
507 status_t
508 DVBMediaNode::FormatProposal(const media_source &source, media_format *format)
509 {
510 	TRACE("DVBMediaNode::FormatProposal: %s\n", SourceDefaultName(source));
511 
512 	/* The connection process:
513 	 * we are here => BBufferProducer::FormatProposal
514 	 *                BBufferConsumer::AcceptFormat
515 	 *                BBufferProducer::PrepareToConnect
516 	 *                BBufferConsumer::Connected
517 	 *                BBufferProducer::Connect
518 	 *
519 	 * What we need to do:
520 	 * - if the format contains a wildcard AND we have a requirement for that
521 	 *   field, set it to the value we need.
522 	 * - if a field has a value that is not wildcard and not supported by us,
523 	 *   we don't change it, and return B_MEDIA_BAD_FORMAT
524 	 * - after we are done, the format may still contain wildcards.
525 	 */
526 
527 	if (source.port != ControlPort())
528 		goto _bad_source;
529 
530 	#ifdef DEBUG
531 		TRACE("proposed format: ");
532 		PrintFormat(*format);
533 		TRACE("required format: ");
534 		switch (source.id) {
535 			case ID_RAW_VIDEO:
536 				PrintFormat(fRequiredFormatRawVideo);
537 				break;
538 
539 			case ID_RAW_AUDIO:
540 				PrintFormat(fRequiredFormatRawAudio);
541 				break;
542 
543 			case ID_ENC_VIDEO:
544 				PrintFormat(fRequiredFormatEncVideo);
545 				break;
546 
547 			case ID_ENC_AUDIO:
548 				PrintFormat(fRequiredFormatEncAudio);
549 				break;
550 
551 			case ID_TS:
552 				PrintFormat(fRequiredFormatTS);
553 				break;
554 		}
555 	#endif
556 
557 	switch (source.id) {
558 		case ID_RAW_VIDEO:
559 			// check if destination still available
560 			if (fOutputRawVideo.destination != media_destination::null)
561 				goto _bad_source;
562 			// set requirements and check if compatible
563 			color_space c;
564 			c = format->u.raw_video.display.format;
565 			format->SpecializeTo(&fRequiredFormatRawVideo);
566 			format->u.raw_video.display.format = c;
567 //			if (!format->Matches(&fRequiredFormatRawVideo))
568 //				goto _bad_format_1;
569 			if (!VerifyFormatRawVideo(format->u.raw_video))
570 				goto _bad_format_2;
571 			break;
572 
573 		case ID_RAW_AUDIO:
574 			// check if destination still available
575 			if (fOutputRawAudio.destination != media_destination::null)
576 				goto _bad_source;
577 			// set requirements and check if compatible
578 			format->SpecializeTo(&fRequiredFormatRawAudio);
579 			if (!format->Matches(&fRequiredFormatRawAudio))
580 				goto _bad_format_1;
581 			if (!VerifyFormatRawAudio(format->u.raw_audio))
582 				goto _bad_format_2;
583 			break;
584 
585 		case ID_ENC_VIDEO:
586 			// check if destination still available
587 			if (fOutputEncVideo.destination != media_destination::null)
588 				goto _bad_source;
589 			// set requirements and check if compatible
590 			format->SpecializeTo(&fRequiredFormatEncVideo);
591 			if (!format->Matches(&fRequiredFormatEncVideo))
592 				goto _bad_format_1;
593 			break;
594 
595 		case ID_ENC_AUDIO:
596 			// check if destination still available
597 			if (fOutputEncAudio.destination != media_destination::null)
598 				goto _bad_source;
599 			// set requirements and check if compatible
600 			format->SpecializeTo(&fRequiredFormatEncAudio);
601 			if (!format->Matches(&fRequiredFormatEncAudio))
602 				goto _bad_format_1;
603 			break;
604 
605 		case ID_TS:
606 			// check if destination still available
607 			if (fOutputTS.destination != media_destination::null)
608 				goto _bad_source;
609 			// set requirements and check if compatible
610 			format->SpecializeTo(&fRequiredFormatTS);
611 			if (!format->Matches(&fRequiredFormatTS))
612 				goto _bad_format_1;
613 			break;
614 
615 		default:
616 			goto _bad_source;
617 	}
618 
619 	#ifdef DEBUG
620 		TRACE("final format: ");
621 		PrintFormat(*format);
622 	#endif
623 
624 	return B_OK;
625 
626 _bad_source:
627 	TRACE("Error: bad source!\n");
628 	return B_MEDIA_BAD_SOURCE;
629 
630 _bad_format_1:
631 	TRACE("Error, bad format (1): ");
632 	goto _bad_format;
633 
634 _bad_format_2:
635 	TRACE("Error, bad format (2): ");
636 	goto _bad_format;
637 
638 _bad_format:
639 	#ifdef DEBUG
640 		PrintFormat(*format);
641 	#endif
642 	return B_MEDIA_BAD_FORMAT;
643 }
644 
645 
646 status_t
647 DVBMediaNode::PrepareToConnect(const media_source &source,
648 		const media_destination &destination, media_format *format,
649 		media_source *out_source, char *out_name)
650 {
651 	/* The connection process:
652 	 *                BBufferProducer::FormatProposal
653 	 *                BBufferConsumer::AcceptFormat
654 	 * we are here => BBufferProducer::PrepareToConnect
655 	 *                BBufferConsumer::Connected
656 	 *                BBufferProducer::Connect
657 	 *
658 	 * At this point, the consumer's AcceptFormat() method has been called,
659 	 * and that node has potentially changed the proposed format. It may
660 	 * also have left wildcards in the format. PrepareToConnect()
661 	 * *must* fully specialize the format before returning!
662 	 */
663 
664 	TRACE("DVBMediaNode::PrepareToConnect: %s\n", SourceDefaultName(source));
665 
666 	#ifdef DEBUG
667 		TRACE("connecting format: ");
668 		PrintFormat(*format);
669 		TRACE("required format: ");
670 		switch (source.id) {
671 			case ID_RAW_VIDEO:
672 				PrintFormat(fRequiredFormatRawVideo);
673 				break;
674 
675 			case ID_RAW_AUDIO:
676 				PrintFormat(fRequiredFormatRawAudio);
677 				break;
678 
679 			case ID_ENC_VIDEO:
680 				PrintFormat(fRequiredFormatEncVideo);
681 				break;
682 
683 			case ID_ENC_AUDIO:
684 				PrintFormat(fRequiredFormatEncAudio);
685 				break;
686 
687 			case ID_TS:
688 				PrintFormat(fRequiredFormatTS);
689 				break;
690 		}
691 	#endif
692 
693 	// is the source valid?
694 	if (source.port != ControlPort())
695 		goto _bad_source;
696 
697 	// 1) check if the output is still available,
698 	// 2) specialize and verify the format
699 	switch (source.id) {
700 		case ID_RAW_VIDEO:
701 			if (fOutputRawVideo.destination != media_destination::null)
702 				goto _already_connected;
703 			SpecializeFormatRawVideo(&format->u.raw_video);
704 //			if (!format->Matches(&fRequiredFormatRawVideo))
705 //				goto _bad_format;
706 			if (!VerifyFormatRawVideo(format->u.raw_video))
707 				goto _bad_format;
708 			break;
709 
710 		case ID_RAW_AUDIO:
711 			if (fOutputRawAudio.destination != media_destination::null)
712 				goto _already_connected;
713 			SpecializeFormatRawAudio(&format->u.raw_audio);
714 			if (!format->Matches(&fRequiredFormatRawAudio))
715 				goto _bad_format;
716 			if (!VerifyFormatRawAudio(format->u.raw_audio))
717 				goto _bad_format;
718 			break;
719 
720 		case ID_ENC_VIDEO:
721 			if (fOutputEncVideo.destination != media_destination::null)
722 				goto _already_connected;
723 			SpecializeFormatEncVideo(&format->u.encoded_video);
724 			if (!format->Matches(&fRequiredFormatEncVideo))
725 				goto _bad_format;
726 			break;
727 
728 		case ID_ENC_AUDIO:
729 			if (fOutputEncAudio.destination != media_destination::null)
730 				goto _already_connected;
731 			SpecializeFormatEncAudio(&format->u.encoded_audio);
732 			if (!format->Matches(&fRequiredFormatRawVideo))
733 				goto _bad_format;
734 			break;
735 
736 		case ID_TS:
737 			if (fOutputTS.destination != media_destination::null)
738 				goto _already_connected;
739 			SpecializeFormatTS(&format->u.multistream);
740 			if (!format->Matches(&fRequiredFormatTS))
741 				goto _bad_format;
742 			break;
743 
744 		default:
745 			goto _bad_source;
746 	}
747 
748 	#ifdef DEBUG
749 		TRACE("final format: ");
750 		PrintFormat(*format);
751 	#endif
752 
753 	// reserve the connection by setting destination
754 	// set the output's format to the new format
755 	SetOutput(source, destination, *format);
756 
757 	// set source and suggest a name
758 	*out_source = source;
759 	strcpy(out_name, SourceDefaultName(source));
760 
761 	return B_OK;
762 
763 _bad_source:
764 	TRACE("Error: bad source!\n");
765 	return B_MEDIA_BAD_SOURCE;
766 
767 _bad_format:
768 	#ifdef DEBUG
769 		TRACE("Error, bad format: ");
770 		PrintFormat(*format);
771 	#endif
772 	return B_MEDIA_BAD_FORMAT;
773 
774 _already_connected:
775 	TRACE("Error: already connected!\n");
776 	return B_MEDIA_ALREADY_CONNECTED;
777 }
778 
779 
780 void
781 DVBMediaNode::Connect(status_t error, const media_source &source,
782 		const media_destination &destination, const media_format &format,
783 		char *io_name)
784 {
785 	/* The connection process:
786 	 *                BBufferProducer::FormatProposal
787 	 *                BBufferConsumer::AcceptFormat
788 	 *                BBufferProducer::PrepareToConnect
789 	 *                BBufferConsumer::Connected
790 	 * we are here => BBufferProducer::Connect
791 	 */
792 
793 	TRACE("DVBMediaNode::Connect: %s\n", SourceDefaultName(source));
794 
795 	if (error != B_OK) {
796 		TRACE("Error during connecting\n");
797 		// if an error occured, unreserve the connection
798 		ResetOutput(source);
799 		return;
800 	}
801 
802 	#ifdef DEBUG
803 		TRACE("connected format: ");
804 		PrintFormat(format);
805 	#endif
806 
807 	// Since the destination is allowed to be changed by the
808 	// consumer, the one we got in PrepareToConnect() is no
809 	// longer correct, and must be updated here.
810 	SetOutput(source, destination, format);
811 
812 	// Set output as connected
813 	switch (source.id) {
814 		case ID_RAW_VIDEO:
815 			fOutputEnabledRawVideo = true;
816 			break;
817 
818 		case ID_RAW_AUDIO:
819 			fOutputEnabledRawAudio = true;
820 			break;
821 
822 		case ID_ENC_VIDEO:
823 			fOutputEnabledEncVideo = true;
824 			break;
825 
826 		case ID_ENC_AUDIO:
827 			fOutputEnabledEncAudio = true;
828 			break;
829 
830 		case ID_TS:
831 			fOutputEnabledTS = true;
832 			break;
833 
834 		default:
835 			break;
836 	}
837 
838 	// if the connection has no name, we set it now
839 	if (strlen(io_name) == 0)
840 		strcpy(io_name, SourceDefaultName(source));
841 
842 	#ifdef DEBUG
843 		bigtime_t latency;
844 		media_node_id ts;
845 		if (B_OK != FindLatencyFor(destination, &latency, &ts))
846 			TRACE("FindLatencyFor failed\n");
847 		else
848 			TRACE("downstream latency %Ld\n", latency);
849 	#endif
850 }
851 
852 
853 void
854 DVBMediaNode::Disconnect(const media_source &source,
855 		const media_destination &destination)
856 {
857 	TRACE("DVBMediaNode::Disconnect: %s\n", SourceDefaultName(source));
858 
859 	// unreserve the connection
860 	ResetOutput(source);
861 
862 	// Set output to disconnected
863 	switch (source.id) {
864 		case ID_RAW_VIDEO:
865 			fOutputEnabledRawVideo = false;
866 			break;
867 
868 		case ID_RAW_AUDIO:
869 			fOutputEnabledRawAudio = false;
870 			break;
871 
872 		case ID_ENC_VIDEO:
873 			fOutputEnabledEncVideo = false;
874 			break;
875 
876 		case ID_ENC_AUDIO:
877 			fOutputEnabledEncAudio = false;
878 			break;
879 
880 		case ID_TS:
881 			fOutputEnabledTS = false;
882 			break;
883 
884 		default:
885 			break;
886 	}
887 }
888 
889 
890 void
891 DVBMediaNode::LateNoticeReceived(const media_source &source,
892 		bigtime_t how_much, bigtime_t performance_time)
893 {
894 	TRACE("DVBMediaNode::LateNoticeReceived %Ld late at %Ld\n", how_much,
895 		performance_time);
896 }
897 
898 
899 void
900 DVBMediaNode::EnableOutput(const media_source &source, bool enabled,
901 		int32 *_deprecated_)
902 {
903 	TRACE("DVBMediaNode::EnableOutput id = %ld, enabled = %d\n", source.id,
904 		enabled);
905 	/* not used yet
906 	switch (source.id) {
907 		case ID_RAW_VIDEO:	fOutputEnabledRawVideo = enabled; break;
908 		case ID_RAW_AUDIO:	fOutputEnabledRawAudio = enabled; break;
909 		case ID_ENC_VIDEO:	fOutputEnabledEncVideo = enabled; break;
910 		case ID_ENC_AUDIO:	fOutputEnabledEncAudio = enabled; break;
911 		case ID_TS:			fOutputEnabledTS = enabled; break;
912 		default:			break;
913 	}
914 	*/
915 }
916 
917 
918 status_t
919 DVBMediaNode::SetPlayRate(int32 numer, int32 denom)
920 {
921 
922 	return B_ERROR;
923 }
924 
925 
926 void
927 DVBMediaNode::AdditionalBufferRequested(const media_source &source,
928 		media_buffer_id prev_buffer, bigtime_t prev_time,
929 		const media_seek_tag *prev_tag)
930 {
931 	TRACE("DVBMediaNode::AdditionalBufferRequested: %s\n",
932 		SourceDefaultName(source));
933 }
934 
935 
936 void
937 DVBMediaNode::LatencyChanged(const media_source &source,
938 		const media_destination &destination, bigtime_t new_latency,
939 		uint32 flags)
940 {
941 	TRACE("DVBMediaNode::LatencyChanged to %Ld\n", new_latency);
942 }
943 
944 /* DVBMediaNode */
945 
946 
947 void
948 DVBMediaNode::HandleTimeWarp(bigtime_t performance_time)
949 {
950 	TRACE("DVBMediaNode::HandleTimeWarp at %Ld\n", performance_time);
951 }
952 
953 
954 void
955 DVBMediaNode::HandleSeek(bigtime_t performance_time)
956 {
957 	TRACE("DVBMediaNode::HandleSeek at %Ld\n", performance_time);
958 }
959 
960 
961 void
962 DVBMediaNode::InitDefaultFormats()
963 {
964 	// 720 * 576
965 	fDefaultFormatRawVideo.type = B_MEDIA_RAW_VIDEO;
966 	fDefaultFormatRawVideo.u.raw_video.display.format = B_RGB32;
967 	fDefaultFormatRawVideo.u.raw_video.display.line_width = 720;
968 	fDefaultFormatRawVideo.u.raw_video.display.line_count = 576;
969 	fDefaultFormatRawVideo.u.raw_video.last_active
970 		= fDefaultFormatRawVideo.u.raw_video.display.line_count - 1;
971 	fDefaultFormatRawVideo.u.raw_video.display.bytes_per_row
972 		= fDefaultFormatRawVideo.u.raw_video.display.line_width * 4;
973 	fDefaultFormatRawVideo.u.raw_video.field_rate = 0;
974 		// wildcard
975 	fDefaultFormatRawVideo.u.raw_video.interlace = 1;
976 	fDefaultFormatRawVideo.u.raw_video.first_active = 0;
977 	fDefaultFormatRawVideo.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
978 	fDefaultFormatRawVideo.u.raw_video.pixel_width_aspect = 1;
979 	fDefaultFormatRawVideo.u.raw_video.pixel_height_aspect = 1;
980 	fDefaultFormatRawVideo.u.raw_video.display.pixel_offset = 0;
981 	fDefaultFormatRawVideo.u.raw_video.display.line_offset = 0;
982 	fDefaultFormatRawVideo.u.raw_video.display.flags = 0;
983 
984 	fDefaultFormatRawAudio.type = B_MEDIA_RAW_AUDIO;
985 	fDefaultFormatRawAudio.u.raw_audio.frame_rate = 48000;
986 	fDefaultFormatRawAudio.u.raw_audio.channel_count = 2;
987 //  XXX broken in Haiku...
988 //	fDefaultFormatRawAudio.u.raw_audio.format = 0; // wildcard
989 	fDefaultFormatRawAudio.u.raw_audio.format
990 		= media_raw_audio_format::B_AUDIO_SHORT;
991 //  when set to 0, haiku mixer has problems when diung a format change
992 //  set to short and debug the buffer_size problem first!
993 	fDefaultFormatRawAudio.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
994 //	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 0; // wildcard
995 //	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 0x1200;
996 //	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 0x1000;
997 	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 32768;
998 //	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 333 * 8;
999 //	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 512;
1000 //  when set to anything different from 32768 haiku mixer has problems
1001 
1002 	fDefaultFormatEncVideo.type = B_MEDIA_ENCODED_VIDEO;
1003 	fDefaultFormatEncAudio.type = B_MEDIA_ENCODED_AUDIO;
1004 	fDefaultFormatTS.type = B_MEDIA_MULTISTREAM;
1005 }
1006 
1007 
1008 bool
1009 DVBMediaNode::VerifyFormatRawVideo(const media_raw_video_format &format)
1010 {
1011 	if (format.display.format != 0 &&
1012 		format.display.format != B_RGB32 &&
1013 		format.display.format != B_YCbCr422)
1014 		return false;
1015 
1016 	return true;
1017 }
1018 
1019 
1020 bool
1021 DVBMediaNode::VerifyFormatRawAudio(const media_multi_audio_format &format)
1022 {
1023 	if (format.format != 0 &&
1024 		format.format != media_raw_audio_format::B_AUDIO_FLOAT &&
1025 		format.format != media_raw_audio_format::B_AUDIO_SHORT)
1026 		return false;
1027 
1028 	return true;
1029 }
1030 
1031 
1032 void
1033 DVBMediaNode::SpecializeFormatRawVideo(media_raw_video_format *format)
1034 {
1035 	// Here we need to specialize *all* remaining wildcard
1036 	// fields that the consumer didn't set
1037 	if (format->field_rate == 0.0)
1038 		format->field_rate = 25;
1039 
1040 	// XXX a lot is missing here...
1041 }
1042 
1043 
1044 void
1045 DVBMediaNode::SpecializeFormatRawAudio(media_multi_audio_format *format)
1046 {
1047 	// Here we need to specialize *all* remaining wildcard
1048 	// fields that the consumer didn't set
1049 	if (format->format == 0)
1050 		format->format = media_raw_audio_format::B_AUDIO_SHORT;
1051 
1052 	if (format->buffer_size == 0)
1053 		format->buffer_size = 333 * 8;
1054 
1055 	// XXX a lot is missing here...
1056 }
1057 
1058 
1059 void
1060 DVBMediaNode::SpecializeFormatEncVideo(media_encoded_video_format *format)
1061 {
1062 	// Here we need to specialize *all* remaining wildcard
1063 	// fields that the consumer didn't set
1064 }
1065 
1066 
1067 void
1068 DVBMediaNode::SpecializeFormatEncAudio(media_encoded_audio_format *format)
1069 {
1070 	// Here we need to specialize *all* remaining wildcard
1071 	// fields that the consumer didn't set
1072 }
1073 
1074 
1075 void
1076 DVBMediaNode::SpecializeFormatTS(media_multistream_format *format)
1077 {
1078 	// Here we need to specialize *all* remaining wildcard
1079 	// fields that the consumer didn't set
1080 }
1081 
1082 
1083 status_t
1084 DVBMediaNode::SetOutput(const media_source &source,
1085 	const media_destination &destination, const media_format &format)
1086 {
1087 	switch (source.id) {
1088 		case ID_RAW_VIDEO:
1089 			fOutputRawVideo.destination = destination;
1090 			fOutputRawVideo.format = format;
1091 			break;
1092 
1093 		case ID_RAW_AUDIO:
1094 			fOutputRawAudio.destination = destination;
1095 			fOutputRawAudio.format = format;
1096 			break;
1097 
1098 		case ID_ENC_VIDEO:
1099 			fOutputEncVideo.destination = destination;
1100 			fOutputEncVideo.format = format;
1101 			break;
1102 
1103 		case ID_ENC_AUDIO:
1104 			fOutputEncAudio.destination = destination;
1105 			fOutputEncAudio.format = format;
1106 			break;
1107 
1108 		case ID_TS:
1109 			fOutputTS.destination = destination;
1110 			fOutputTS.format = format;
1111 			break;
1112 
1113 		default:
1114 			return B_MEDIA_BAD_SOURCE;
1115 	}
1116 	return B_OK;
1117 }
1118 
1119 
1120 status_t
1121 DVBMediaNode::ResetOutput(const media_source &source)
1122 {
1123 	switch (source.id) {
1124 		case ID_RAW_VIDEO:
1125 			fOutputRawVideo.destination = media_destination::null;
1126 			fOutputRawVideo.format = fDefaultFormatRawVideo;
1127 			break;
1128 
1129 		case ID_RAW_AUDIO:
1130 			fOutputRawAudio.destination = media_destination::null;
1131 			fOutputRawAudio.format = fDefaultFormatRawAudio;
1132 			break;
1133 
1134 		case ID_ENC_VIDEO:
1135 			fOutputEncVideo.destination = media_destination::null;
1136 			fOutputEncVideo.format = fDefaultFormatEncVideo;
1137 			break;
1138 
1139 		case ID_ENC_AUDIO:
1140 			fOutputEncAudio.destination = media_destination::null;
1141 			fOutputEncAudio.format = fDefaultFormatEncAudio;
1142 			break;
1143 
1144 		case ID_TS:
1145 			fOutputTS.destination = media_destination::null;
1146 			fOutputTS.format = fDefaultFormatTS;
1147 			break;
1148 
1149 		default:
1150 			return B_MEDIA_BAD_SOURCE;
1151 	}
1152 	return B_OK;
1153 }
1154 
1155 
1156 const char *
1157 DVBMediaNode::SourceDefaultName(const media_source &source)
1158 {
1159 	switch (source.id) {
1160 		case ID_RAW_VIDEO:
1161 			return "raw video";
1162 
1163 		case ID_RAW_AUDIO:
1164 			return "raw audio";
1165 
1166 		case ID_ENC_VIDEO:
1167 			return "encoded video";
1168 
1169 		case ID_ENC_AUDIO:
1170 			return "encoded audio";
1171 
1172 		case ID_TS:
1173 			return "MPEG2 TS";
1174 
1175 		default:
1176 			return NULL;
1177 	}
1178 }
1179 
1180 
1181 void
1182 DVBMediaNode::HandleStart(bigtime_t performance_time)
1183 {
1184 	TRACE("DVBMediaNode::HandleStart\n");
1185 	StartCapture();
1186 }
1187 
1188 
1189 void
1190 DVBMediaNode::HandleStop(void)
1191 {
1192 	TRACE("DVBMediaNode::HandleStop\n");
1193 	StopCapture();
1194 }
1195 
1196 
1197 status_t
1198 DVBMediaNode::Tune()
1199 {
1200 	TRACE("DVBMediaNode::Tune enter\n");
1201 
1202 	TRACE("state %d, region %d, channel %d, audio %d\n",
1203 		fSelectedState, fSelectedRegion, fSelectedChannel, fSelectedAudio);
1204 
1205 	status_t err;
1206 	bool needs_tuning = false;
1207 
1208 	if (fSelectedChannel < 0 || fSelectedAudio < 0) {
1209 		printf("DVBMediaNode::Tune: invalid tuning info\n");
1210 		StopCapture();
1211 		err = B_ERROR;
1212 		goto end;
1213 //		return B_ERROR;
1214 	}
1215 
1216 	const char *desc;
1217 
1218 	dvb_tuning_parameters_t new_params;
1219 	int new_video_pid;
1220 	int new_audio_pid;
1221 	int new_pcr_pid;
1222 
1223 	desc = fChannelList->ItemAt(fSelectedChannel);
1224 	err = ExtractTuningParams(desc, fSelectedAudio, &new_params,
1225 		&new_video_pid, &new_audio_pid, &new_pcr_pid);
1226 
1227 	if (err != B_OK) {
1228 		printf("DVBMediaNode::Tune: getting tuning info failed\n");
1229 		StopCapture();
1230 		err = B_ERROR;
1231 		goto end;
1232 //		return B_ERROR;
1233 	}
1234 /*
1235 	if (fTuningParam.frequency == new_params.frequency) {
1236 		printf("DVBMediaNode::Tune: frequency not changed\n");
1237 		fVideoPid = new_video_pid;
1238 		fAudioPid = new_audio_pid;
1239 		fPcrPid = new_pcr_pid;
1240 		fDemux->SetPIDs(fVideoPid, fAudioPid, fPcrPid);
1241 		return B_OK;
1242 	}
1243 */
1244 	switch (fInterfaceType) {
1245 		case DVB_TYPE_DVB_T:
1246 			needs_tuning = (fTuningParam.u.dvb_t.frequency
1247 					!= new_params.u.dvb_t.frequency) || !fTuningSuccess;
1248 			needs_tuning = true;
1249 			break;
1250 
1251 		case DVB_TYPE_DVB_S:
1252 			printf("needs_tuning = %d, forcing tuning for DVB-S\n",
1253 				needs_tuning);
1254 			needs_tuning = true;
1255 			break;
1256 
1257 		default:
1258 			needs_tuning = true;
1259 			break;
1260 	}
1261 
1262 	fTuningParam = new_params;
1263 	fVideoPid = new_video_pid;
1264 	fAudioPid = new_audio_pid;
1265 	fPcrPid = new_pcr_pid;
1266 
1267 	if (needs_tuning) {
1268 printf("about to stop capture 1\n");
1269 #if STOP_CAPTURE_WHILE_TUNING
1270 printf("about to stop capture 2\n");
1271 		err = StopCapture();
1272 		if (err) {
1273 			printf("Tune: StopCapture failed\n");
1274 			goto end;
1275 		}
1276 #endif
1277 	} else {
1278 #if STOP_CAPTURE_WHILE_TUNING
1279 		StopCaptureThreads();
1280 #endif
1281 	}
1282 
1283 	if (needs_tuning) {
1284 		err = fCard->SetTuningParameter(fTuningParam);
1285 		fTuningSuccess = err == B_OK;
1286 	}
1287 
1288 	fDemux->SetPIDs(fVideoPid, fAudioPid, fPcrPid);
1289 
1290 	if (needs_tuning) {
1291 		if (fTuningSuccess) {
1292 			fCard->GetTuningParameter(&fTuningParam);
1293 			err = StartCapture();
1294 		}
1295 	} else {
1296 #if STOP_CAPTURE_WHILE_TUNING
1297 		StartCaptureThreads();
1298 #endif
1299 	}
1300 
1301 end:
1302 	EventQueue()->AddEvent(media_timed_event(0, M_REFRESH_PARAMETER_WEB));
1303 //	RefreshParameterWeb();
1304 
1305 	TRACE("DVBMediaNode::Tune finished\n");
1306 	return err;
1307 }
1308 
1309 
1310 status_t
1311 DVBMediaNode::StartCapture()
1312 {
1313 	TRACE("DVBMediaNode::StartCapture\n");
1314 
1315 	if (fCaptureActive)
1316 		return B_OK;
1317 
1318 	RETURN_IF_ERROR(StopCaptureThreads());
1319 
1320 	if (!fTuningSuccess) {
1321 		RETURN_IF_ERROR(Tune());
1322 	}
1323 
1324 	RETURN_IF_ERROR(StartCaptureThreads());
1325 
1326 	fCard->CaptureStart();
1327 
1328 	fCaptureActive = true;
1329 
1330 	RefreshParameterWeb();
1331 
1332 	return B_OK;
1333 }
1334 
1335 
1336 status_t
1337 DVBMediaNode::StopCapture()
1338 {
1339 	TRACE("DVBMediaNode::StopCapture\n");
1340 	if (!fCaptureActive)
1341 		return B_OK;
1342 
1343 	StopCaptureThreads();
1344 
1345 	fCard->CaptureStop();
1346 
1347 	fCaptureActive = false;
1348 	return B_OK;
1349 }
1350 
1351 
1352 status_t
1353 DVBMediaNode::StartCaptureThreads()
1354 {
1355 	TRACE("DVBMediaNode::StartCaptureThreads\n");
1356 
1357 	if (fCaptureThreadsActive)
1358 		return B_OK;
1359 
1360 	fTerminateThreads = false;
1361 
1362 	fThreadIdCardReader = spawn_thread(_card_reader_thread_, "DVB card reader",
1363 		120, this);
1364 	fThreadIdMpegDemux = spawn_thread(_mpeg_demux_thread_, "DVB MPEG demux",
1365 		110, this);
1366 	fThreadIdEncAudio = spawn_thread(_enc_audio_thread_, "DVB audio streaming",
1367 		110, this);
1368 	fThreadIdEncVideo = spawn_thread(_enc_video_thread_, "DVB video streaming",
1369 		110, this);
1370 	fThreadIdMpegTS = spawn_thread(_mpeg_ts_thread_, "DVB MPEG TS streaming",
1371 		110, this);
1372 	fThreadIdRawAudio = spawn_thread(_raw_audio_thread_, "DVB audio decode",
1373 		100, this);
1374 	fThreadIdRawVideo = spawn_thread(_raw_video_thread_, "DVB video decode",
1375 		85, this);
1376 	resume_thread(fThreadIdCardReader);
1377 	resume_thread(fThreadIdMpegDemux);
1378 	resume_thread(fThreadIdEncAudio);
1379 	resume_thread(fThreadIdEncVideo);
1380 	resume_thread(fThreadIdMpegTS);
1381 	resume_thread(fThreadIdRawAudio);
1382 	resume_thread(fThreadIdRawVideo);
1383 
1384 	fCaptureThreadsActive = true;
1385 	return B_OK;
1386 }
1387 
1388 
1389 status_t
1390 DVBMediaNode::StopCaptureThreads()
1391 {
1392 	TRACE("DVBMediaNode::StopCaptureThreads\n");
1393 
1394 	if (!fCaptureThreadsActive)
1395 		return B_OK;
1396 
1397 	fTerminateThreads = true;
1398 
1399 	fCardDataQueue->Terminate();
1400 	fEncVideoQueue->Terminate();
1401 	fEncAudioQueue->Terminate();
1402 	fMpegTsQueue->Terminate();
1403 	fRawVideoQueue->Terminate();
1404 	fRawAudioQueue->Terminate();
1405 
1406 	status_t dummy; // NULL as parameter does not work
1407 	wait_for_thread(fThreadIdCardReader, &dummy);
1408 	wait_for_thread(fThreadIdMpegDemux, &dummy);
1409 	wait_for_thread(fThreadIdEncAudio, &dummy);
1410 	wait_for_thread(fThreadIdEncVideo, &dummy);
1411 	wait_for_thread(fThreadIdMpegTS, &dummy);
1412 	wait_for_thread(fThreadIdRawAudio, &dummy);
1413 	wait_for_thread(fThreadIdRawVideo, &dummy);
1414 
1415 	fCardDataQueue->Restart();
1416 	fEncVideoQueue->Restart();
1417 	fEncAudioQueue->Restart();
1418 	fMpegTsQueue->Restart();
1419 	fRawVideoQueue->Restart();
1420 	fRawAudioQueue->Restart();
1421 
1422 	fCaptureThreadsActive = false;
1423 	return B_OK;
1424 }
1425 
1426 
1427 int32
1428 DVBMediaNode::_card_reader_thread_(void *arg)
1429 {
1430 	static_cast<DVBMediaNode *>(arg)->card_reader_thread();
1431 	return 0;
1432 }
1433 
1434 
1435 int32
1436 DVBMediaNode::_mpeg_demux_thread_(void *arg)
1437 {
1438 	static_cast<DVBMediaNode *>(arg)->mpeg_demux_thread();
1439 	return 0;
1440 }
1441 
1442 
1443 int32
1444 DVBMediaNode::_raw_audio_thread_(void *arg)
1445 {
1446 	static_cast<DVBMediaNode *>(arg)->raw_audio_thread();
1447 	return 0;
1448 }
1449 
1450 
1451 int32
1452 DVBMediaNode::_raw_video_thread_(void *arg)
1453 {
1454 	static_cast<DVBMediaNode *>(arg)->raw_video_thread();
1455 	return 0;
1456 }
1457 
1458 
1459 int32
1460 DVBMediaNode::_enc_audio_thread_(void *arg)
1461 {
1462 	static_cast<DVBMediaNode *>(arg)->enc_audio_thread();
1463 	return 0;
1464 }
1465 
1466 
1467 int32
1468 DVBMediaNode::_enc_video_thread_(void *arg)
1469 {
1470 	static_cast<DVBMediaNode *>(arg)->enc_video_thread();
1471 	return 0;
1472 }
1473 
1474 
1475 int32
1476 DVBMediaNode::_mpeg_ts_thread_(void *arg)
1477 {
1478 	static_cast<DVBMediaNode *>(arg)->mpeg_ts_thread();
1479 	return 0;
1480 }
1481 
1482 
1483 void
1484 DVBMediaNode::card_reader_thread()
1485 {
1486 	while (!fTerminateThreads) {
1487 		void *data;
1488 		size_t size;
1489 		status_t err;
1490 		bigtime_t end_time;
1491 		err = fCard->Capture(&data, &size, &end_time);
1492 		if (err != B_OK) {
1493 			TRACE("fCard->Capture failed, error %lx (%s)\n", err,
1494 				strerror(err));
1495 			continue;
1496 		}
1497 
1498 //		TRACE("captured %ld bytes\n", size);
1499 
1500 		Packet *packet = new Packet(data, size, end_time);
1501 
1502 		err = fCardDataQueue->Insert(packet);
1503 		if (err != B_OK) {
1504 			delete packet;
1505 			TRACE("fCardDataQueue->Insert failed, error %lx\n", err);
1506 			continue;
1507 		}
1508 	}
1509 }
1510 
1511 
1512 void
1513 DVBMediaNode::mpeg_demux_thread()
1514 {
1515 	while (!fTerminateThreads) {
1516 		status_t err;
1517 		Packet *packet;
1518 		err = fCardDataQueue->Remove(&packet);
1519 		if (err != B_OK) {
1520 			TRACE("fCardDataQueue->Remove failed, error %lx\n", err);
1521 			continue;
1522 		}
1523 
1524 		// packet->TimeStamp() is the end time of the capture
1525 		fDemux->AddData(packet);
1526 	}
1527 }
1528 
1529 
1530 void
1531 DVBMediaNode::mpeg_ts_thread()
1532 {
1533 	while (!fTerminateThreads) {
1534 		status_t err;
1535 		Packet *packet;
1536 		err = fMpegTsQueue->Remove(&packet);
1537 		if (err != B_OK) {
1538 			TRACE("fMpegTsQueue->Remove failed, error %lx\n", err);
1539 			continue;
1540 		}
1541 
1542 //		TRACE("mpeg ts   packet, size %6ld, start_time %14Ld\n",
1543 //			packet->Size(), packet->TimeStamp());
1544 
1545 #ifdef DUMP_MPEG_TS
1546 		lock.Lock();
1547 		write(fMpegTsFile, packet->Data(), packet->Size());
1548 		lock.Unlock();
1549 #endif
1550 
1551 		delete packet;
1552 	}
1553 }
1554 
1555 
1556 void
1557 DVBMediaNode::enc_audio_thread()
1558 {
1559 	while (!fTerminateThreads) {
1560 		status_t err;
1561 		Packet *packet;
1562 		err = fEncAudioQueue->Remove(&packet);
1563 		if (err != B_OK) {
1564 			TRACE("fEncAudioQueue->Remove failed, error %lx\n", err);
1565 			continue;
1566 		}
1567 //		TRACE("enc audio packet, size %6ld, start_time %14Ld\n",
1568 //			packet->Size(), packet->TimeStamp());
1569 
1570 #ifdef DUMP_AUDIO
1571 		const uint8 *data;
1572 		size_t size;
1573 		if (B_OK != pes_extract(packet->Data(), packet->Size(), &data,
1574 				&size)) {
1575 			TRACE("audio pes_extract failed\n");
1576 			delete packet;
1577 			return;
1578 		}
1579 		lock.Lock();
1580 		write(fAudioFile, data, size);
1581 		lock.Unlock();
1582 #endif
1583 
1584 		if (!fOutputEnabledEncAudio) {
1585 			delete packet;
1586 			continue;
1587 		}
1588 
1589 		// send encoded audio buffer
1590 
1591 
1592 		delete packet;
1593 	}
1594 }
1595 
1596 
1597 void
1598 DVBMediaNode::enc_video_thread()
1599 {
1600 	while (!fTerminateThreads) {
1601 		status_t err;
1602 		Packet *packet;
1603 		err = fEncVideoQueue->Remove(&packet);
1604 		if (err != B_OK) {
1605 			TRACE("fEncVideoQueue->Remove failed, error %lx\n", err);
1606 			continue;
1607 		}
1608 
1609 //		TRACE("enc video packet, size %6ld, start_time %14Ld\n",
1610 //			packet->Size(), packet->TimeStamp());
1611 
1612 
1613 #ifdef DUMP_VIDEO
1614 		int8 *data;
1615 		size_t size;
1616 		if (B_OK != pes_extract(packet->Data(), packet->Size(), &data,
1617 				&size)) {
1618 			TRACE("video pes_extract failed\n");
1619 			delete packet;
1620 			return;
1621 		}
1622 		lock.Lock();
1623 		write(fVideoFile, data, size);
1624 		lock.Unlock();
1625 #endif
1626 
1627 		if (!fOutputEnabledEncVideo) {
1628 			delete packet;
1629 			continue;
1630 		}
1631 
1632 		// send encoded video buffer
1633 
1634 		delete packet;
1635 	}
1636 }
1637 
1638 
1639 void
1640 DVBMediaNode::raw_audio_thread()
1641 {
1642 	media_format format;
1643 	status_t err;
1644 	err = GetStreamFormat(fRawAudioQueue, &format);
1645 	if (err) {
1646 		printf("fAudioDecoder init error %s\n", strerror(err));
1647 		return;
1648 	}
1649 
1650 	// create decoder interface
1651 
1652 	fAudioDecoder = new MediaStreamDecoder(&_GetNextAudioChunk, this);
1653 
1654 	err = fAudioDecoder->SetInputFormat(format);
1655 	if (err) {
1656 		printf("fAudioDecoder SetInputFormat error %s\n", strerror(err));
1657 		return;
1658 	}
1659 
1660 	TRACE("requested audio decoder format: ");
1661 	PrintFormat(fOutputRawAudio);
1662 
1663 	media_format fmt = fOutputRawAudio.format;
1664 	err = fAudioDecoder->SetOutputFormat(&fmt);
1665 	if (err) {
1666 		printf("fAudioDecoder SetOutputFormat error %s\n", strerror(err));
1667 		return;
1668 	}
1669 
1670 	TRACE("final audio decoder format: ");
1671 	PrintFormat(fmt);
1672 
1673 	// change format of connection
1674 	if (format_is_compatible(fmt, fOutputRawAudio.format)) {
1675 		printf("audio formats are compatible\n");
1676 		fOutputRawAudio.format = fmt;
1677 	} else {
1678 		printf("audio formats NOT compatible\n");
1679 		lock.Lock();
1680 		err = ChangeFormat(fOutputRawAudio.source,
1681 						   fOutputRawAudio.destination,
1682 						   &fmt);
1683 		lock.Unlock();
1684 		printf("format change result %lx (%s)\n", err, strerror(err));
1685 		PrintFormat(fmt);
1686 		fOutputRawAudio.format = fmt;
1687 		if (err)
1688 			return;
1689 	}
1690 
1691 	// decode data and send buffers
1692 
1693 	delete fBufferGroupRawAudio;
1694 	fBufferGroupRawAudio = new BBufferGroup(
1695 		fOutputRawAudio.format.u.raw_audio.buffer_size * 3, 25);
1696 
1697 	while (!fTerminateThreads) {
1698 		int64 frameCount;
1699 		media_header mh;
1700 
1701 		if (!fOutputEnabledRawAudio) {
1702 			fRawAudioQueue->Flush(40000);
1703 			continue;
1704 		}
1705 
1706 		BBuffer* buf;
1707 		buf = fBufferGroupRawAudio->RequestBuffer(
1708 			fOutputRawAudio.format.u.raw_audio.buffer_size,
1709 			AUDIO_BUFFER_REQUEST_TIMEOUT);
1710 		if (!buf) {
1711 			TRACE("audio: request buffer timout\n");
1712 			continue;
1713 		}
1714 
1715 		err = fAudioDecoder->Decode(buf->Data(), &frameCount, &mh, NULL);
1716 		if (err) {
1717 			buf->Recycle();
1718 			printf("fAudioDecoder Decode error %s\n", strerror(err));
1719 			continue;
1720 		}
1721 
1722 #ifdef DUMP_RAW_AUDIO
1723 		lock.Lock();
1724 		write(fRawAudioFile, buf->Data(), mh.size_used);
1725 		lock.Unlock();
1726 #endif
1727 
1728 		if (fOutputRawAudio.format.u.raw_audio.buffer_size != mh.size_used
1729 			|| int(fOutputRawAudio.format.u.raw_audio.frame_rate)
1730 				!= mh.u.raw_audio.frame_rate
1731 			|| fOutputRawAudio.format.u.raw_audio.channel_count
1732 				!= mh.u.raw_audio.channel_count) {
1733 			TRACE("audio: decode format change: changed buffer_size from %ld"
1734 				" to %ld\n", fOutputRawAudio.format.u.raw_audio.buffer_size,
1735 				mh.size_used);
1736 			TRACE("audio: decode format change: changed channel_count from %ld"
1737 				" to %ld\n", fOutputRawAudio.format.u.raw_audio.channel_count,
1738 				mh.u.raw_audio.channel_count);
1739 			TRACE("audio: decode format change: changed frame_rate from %.0f"
1740 				" to %.0f\n", fOutputRawAudio.format.u.raw_audio.frame_rate,
1741 				mh.u.raw_audio.frame_rate);
1742 			fOutputRawAudio.format.u.raw_audio.buffer_size = mh.size_used;
1743 			fOutputRawAudio.format.u.raw_audio.frame_rate
1744 				= mh.u.raw_audio.frame_rate;
1745 			fOutputRawAudio.format.u.raw_audio.channel_count
1746 				= mh.u.raw_audio.channel_count;
1747 			lock.Lock();
1748 			err = ChangeFormat(fOutputRawAudio.source,
1749 				fOutputRawAudio.destination, &fOutputRawAudio.format);
1750 			lock.Unlock();
1751 			printf("format change result %lx (%s)\n", err, strerror(err));
1752 			PrintFormat(fOutputRawAudio.format);
1753 			if (err) {
1754 				buf->Recycle();
1755 				return; // we are dead!
1756 			}
1757 		}
1758 
1759 		bigtime_t ts_perf_time;
1760 		bigtime_t ts_sys_time;
1761 		bigtime_t ts_offset;
1762 		bigtime_t aud_time;
1763 		bigtime_t start_time;
1764 
1765 		// calculate start time of audio data
1766 
1767 		fDemux->TimesourceInfo(&ts_perf_time, &ts_sys_time);
1768 		ts_offset = ts_sys_time - ts_perf_time;
1769 		aud_time = mh.start_time;	// measured in PCR time base
1770 		start_time = TimeSource()->PerformanceTimeFor(aud_time + ts_offset);
1771 
1772 		// calculate delay and wait
1773 
1774 		bigtime_t delay;
1775 		delay = start_time - TimeSource()->Now();
1776 		TRACE_TIMING("audio delay is %Ld\n", delay);
1777 		if (delay < -AUDIO_MAX_LATE) {
1778 			printf("audio: decoded packet is %Ldms too late, dropped\n",
1779 				-delay / 1000);
1780 			buf->Recycle();
1781 			continue;
1782 		}
1783 		if (delay < 0)
1784 //			printf("audio: decoded packet is %Ldms too late\n", -delay / 1000);
1785 
1786 		if (delay > AUDIO_MAX_EARLY) {
1787 			printf("audio: decoded packet is %Ldms too early, dropped\n",
1788 				delay / 1000);
1789 			buf->Recycle();
1790 			continue;
1791 		}
1792 		if (delay > 0)
1793 //			printf("audio: decoded packet is %Ldms too early\n", delay / 1000);
1794 
1795 		delay -= PROCESSING_LATENCY;
1796 		if (delay > 0) {
1797 			if (acquire_sem_etc(fAudioDelaySem, 1, B_RELATIVE_TIMEOUT, delay)
1798 				!= B_TIMED_OUT) {
1799 				printf("audio: delay sem not timed out, dropped packet\n");
1800 				buf->Recycle();
1801 				continue;
1802 			}
1803 		}
1804 
1805 		TRACE_TIMING("audio playback delay %Ld\n",
1806 			start_time - TimeSource()->Now());
1807 
1808 		media_header* hdr;
1809 		hdr = buf->Header();
1810 		hdr->type = B_MEDIA_RAW_AUDIO;
1811 		hdr->size_used = mh.size_used;
1812 		hdr->time_source = TimeSource()->ID();
1813 		hdr->start_time = start_time;
1814 		lock.Lock();
1815 		if (SendBuffer(buf, fOutputRawAudio.source,
1816 			fOutputRawAudio.destination) != B_OK) {
1817 			TRACE("audio: sending buffer failed\n");
1818 			buf->Recycle();
1819 		}
1820 		lock.Unlock();
1821 	}
1822 
1823 	delete fCurrentAudioPacket;
1824 	fCurrentAudioPacket = 0;
1825 }
1826 
1827 
1828 void
1829 DVBMediaNode::raw_video_thread()
1830 {
1831 	media_format format;
1832 	status_t err;
1833 	err = GetStreamFormat(fRawVideoQueue, &format);
1834 	if (err) {
1835 		printf("fVideoDecoder init error %s\n", strerror(err));
1836 		return;
1837 	}
1838 
1839 	// create decoder interface
1840 
1841 	fVideoDecoder = new MediaStreamDecoder(&_GetNextVideoChunk, this);
1842 
1843 	err = fVideoDecoder->SetInputFormat(format);
1844 	if (err) {
1845 		printf("fVideoDecoder SetInputFormat error %s\n", strerror(err));
1846 		return;
1847 	}
1848 
1849 	TRACE("requested video decoder format: ");
1850 	PrintFormat(fOutputRawVideo);
1851 
1852 	media_format fmt = fOutputRawVideo.format;
1853 	err = fVideoDecoder->SetOutputFormat(&fmt);
1854 	if (err) {
1855 		printf("fVideoDecoder SetOutputFormat error %s\n", strerror(err));
1856 		return;
1857 	}
1858 
1859 	TRACE("final video decoder format: ");
1860 	PrintFormat(fmt);
1861 
1862 	// change format of connection
1863 	if (format_is_compatible(fmt, fOutputRawVideo.format)) {
1864 		printf("video formats are compatible\n");
1865 		fOutputRawVideo.format = fmt;
1866 	} else {
1867 		printf("video formats NOT compatible\n");
1868 		lock.Lock();
1869 		err = ChangeFormat(fOutputRawVideo.source,
1870 						   fOutputRawVideo.destination,
1871 						   &fmt);
1872 		lock.Unlock();
1873 		printf("format change result %lx (%s)\n", err, strerror(err));
1874 		PrintFormat(fmt);
1875 		fOutputRawVideo.format = fmt;
1876 		if (err) {
1877 			printf("video format change failed\n");
1878 			return;
1879 		}
1880 	}
1881 
1882 	// decode data and send buffers
1883 
1884 	uint32 video_buffer_size_max = 720 * 576 * 4;
1885 	uint32 video_buffer_size
1886 		= fOutputRawVideo.format.u.raw_video.display.line_count
1887 			* fOutputRawVideo.format.u.raw_video.display.bytes_per_row;
1888 
1889 	delete fBufferGroupRawVideo;
1890 	fBufferGroupRawVideo = new BBufferGroup(video_buffer_size_max, 4);
1891 
1892 	while (!fTerminateThreads) {
1893 		int64 frameCount;
1894 		media_header mh;
1895 
1896 		if (!fOutputEnabledRawVideo) {
1897 			fRawVideoQueue->Flush(40000);
1898 			continue;
1899 		}
1900 
1901 		// fetch a new buffer (always of maximum size as the stream may change)
1902 		BBuffer* buf;
1903 		buf = fBufferGroupRawVideo->RequestBuffer(video_buffer_size_max,
1904 			VIDEO_BUFFER_REQUEST_TIMEOUT);
1905 		if (!buf) {
1906 			TRACE("video: request buffer timout\n");
1907 			continue;
1908 		}
1909 
1910 		// decode one video frame into buffer
1911 		err = fVideoDecoder->Decode(buf->Data(), &frameCount, &mh, NULL);
1912 		if (err) {
1913 			buf->Recycle();
1914 			printf("fVideoDecoder Decode error %s\n", strerror(err));
1915 			continue;
1916 		}
1917 
1918 		// check if the format of the stream has changed
1919 		if (mh.u.raw_video.display_line_width
1920 			!= fOutputRawVideo.format.u.raw_video.display.line_width
1921 			|| mh.u.raw_video.display_line_count
1922 				!= fOutputRawVideo.format.u.raw_video.display.line_count
1923 			|| mh.u.raw_video.bytes_per_row
1924 				!= fOutputRawVideo.format.u.raw_video.display.bytes_per_row
1925 			|| mh.u.raw_video.pixel_width_aspect
1926 				!= fOutputRawVideo.format.u.raw_video.pixel_width_aspect
1927 			|| mh.u.raw_video.pixel_height_aspect
1928 				!= fOutputRawVideo.format.u.raw_video.pixel_height_aspect
1929 			|| mh.size_used != video_buffer_size) {
1930 			printf("video format changed:\n");
1931 			printf(" line_width %ld => %ld\n",
1932 				fOutputRawVideo.format.u.raw_video.display.line_width,
1933 				mh.u.raw_video.display_line_width);
1934 			printf(" line_count %ld => %ld\n",
1935 				fOutputRawVideo.format.u.raw_video.display.line_count,
1936 				mh.u.raw_video.display_line_count);
1937 			printf(" bytes_per_row %ld => %ld\n",
1938 				fOutputRawVideo.format.u.raw_video.display.bytes_per_row,
1939 				mh.u.raw_video.bytes_per_row);
1940 			printf(" pixel_width_aspect %d => %d\n",
1941 				fOutputRawVideo.format.u.raw_video.pixel_width_aspect,
1942 				mh.u.raw_video.pixel_width_aspect);
1943 			printf(" pixel_height_aspect %d => %d\n",
1944 				fOutputRawVideo.format.u.raw_video.pixel_height_aspect,
1945 				mh.u.raw_video.pixel_height_aspect);
1946 			printf(" video_buffer_size %ld => %ld\n", video_buffer_size,
1947 				mh.size_used);
1948 
1949 			// recalculate video buffer size
1950 			video_buffer_size
1951 				= fOutputRawVideo.format.u.raw_video.display.line_count
1952 					* fOutputRawVideo.format.u.raw_video.display.bytes_per_row;
1953 
1954 			// perform a video format change
1955 			fOutputRawVideo.format.u.raw_video.display.line_width
1956 				= mh.u.raw_video.display_line_width;
1957 			fOutputRawVideo.format.u.raw_video.display.line_count
1958 				= mh.u.raw_video.display_line_count;
1959 			fOutputRawVideo.format.u.raw_video.display.bytes_per_row
1960 				= mh.u.raw_video.bytes_per_row;
1961 			fOutputRawVideo.format.u.raw_video.pixel_width_aspect
1962 				= mh.u.raw_video.pixel_width_aspect;
1963 			fOutputRawVideo.format.u.raw_video.pixel_height_aspect
1964 				= mh.u.raw_video.pixel_height_aspect;
1965 			fOutputRawVideo.format.u.raw_video.last_active
1966 				= mh.u.raw_video.display_line_count - 1;
1967 			lock.Lock();
1968 			err = ChangeFormat(fOutputRawVideo.source,
1969 				fOutputRawVideo.destination, &fOutputRawVideo.format);
1970 			lock.Unlock();
1971 			printf("format change result %lx (%s)\n", err, strerror(err));
1972 			PrintFormat(fOutputRawVideo.format);
1973 			if (err) {
1974 				buf->Recycle();
1975 				printf("video format change failed\n");
1976 				return; // we are dead
1977 			}
1978 		}
1979 
1980 		// calculate start time for video
1981 		bigtime_t ts_perf_time;
1982 		bigtime_t ts_sys_time;
1983 		bigtime_t ts_offset;
1984 		bigtime_t pic_time;
1985 		bigtime_t start_time;
1986 
1987 		fDemux->TimesourceInfo(&ts_perf_time, &ts_sys_time);
1988 		ts_offset = ts_sys_time - ts_perf_time;
1989 		pic_time = mh.start_time;	// measured in PCR time base
1990 		start_time = TimeSource()->PerformanceTimeFor(pic_time + ts_offset);
1991 
1992 		// calculate delay and wait
1993 
1994 		bigtime_t delay;
1995 		delay = start_time - TimeSource()->Now();
1996 		TRACE_TIMING("video delay %Ld\n", delay);
1997 		if (delay < -VIDEO_MAX_LATE) {
1998 			printf("video: decoded packet is %Ldms too late, dropped\n",
1999 				-delay / 1000);
2000 			buf->Recycle();
2001 			continue;
2002 		}
2003 		if (delay > VIDEO_MAX_EARLY) {
2004 			printf("video: decoded packet is %Ldms too early, dropped\n",
2005 				delay / 1000);
2006 			buf->Recycle();
2007 			continue;
2008 		}
2009 		delay -= PROCESSING_LATENCY;
2010 		if (delay > 0) {
2011 			if (acquire_sem_etc(fVideoDelaySem, 1, B_RELATIVE_TIMEOUT, delay)
2012 				!= B_TIMED_OUT) {
2013 				printf("video: delay sem not timed out, dropped packet\n");
2014 				buf->Recycle();
2015 				continue;
2016 			}
2017 		}
2018 
2019 		TRACE_TIMING("video playback delay %Ld\n", start_time
2020 			- TimeSource()->Now());
2021 
2022 		media_header* hdr;
2023 		hdr = buf->Header();
2024 		hdr->type = B_MEDIA_RAW_VIDEO;
2025 		hdr->size_used = video_buffer_size;
2026 		hdr->time_source = TimeSource()->ID();
2027 		hdr->start_time = start_time;
2028 		lock.Lock();
2029 		if (SendBuffer(buf, fOutputRawVideo.source,
2030 				fOutputRawVideo.destination) != B_OK) {
2031 			TRACE("video: sending buffer failed\n");
2032 			buf->Recycle();
2033 		}
2034 		lock.Unlock();
2035 	}
2036 
2037 	delete fCurrentVideoPacket;
2038 	fCurrentVideoPacket = 0;
2039 }
2040 
2041 
2042 inline status_t
2043 DVBMediaNode::GetNextVideoChunk(const void **chunkData, size_t *chunkLen,
2044 	media_header *mh)
2045 {
2046 //	TRACE("DVBMediaNode::GetNextVideoChunk\n");
2047 
2048 	delete fCurrentVideoPacket;
2049 
2050 	status_t err;
2051 	err = fRawVideoQueue->Remove(&fCurrentVideoPacket);
2052 	if (err != B_OK) {
2053 		TRACE("fRawVideoQueue->Remove failed, error %lx\n", err);
2054 		fCurrentVideoPacket = 0;
2055 		return B_ERROR;
2056 	}
2057 
2058 	const uint8 *data;
2059 	size_t size;
2060 
2061 	if (B_OK != pes_extract(fCurrentVideoPacket->Data(),
2062 			fCurrentVideoPacket->Size(), &data, &size)) {
2063 		TRACE("video pes_extract failed\n");
2064 		return B_ERROR;
2065 	}
2066 
2067 	*chunkData = data;
2068 	*chunkLen = size;
2069 	// measured in PCR time base
2070 	mh->start_time = fCurrentVideoPacket->TimeStamp();
2071 
2072 	return B_OK;
2073 }
2074 
2075 
2076 inline status_t
2077 DVBMediaNode::GetNextAudioChunk(const void **chunkData, size_t *chunkLen,
2078 	media_header *mh)
2079 {
2080 //	TRACE("DVBMediaNode::GetNextAudioChunk\n");
2081 
2082 	delete fCurrentAudioPacket;
2083 
2084 	status_t err;
2085 	err = fRawAudioQueue->Remove(&fCurrentAudioPacket);
2086 	if (err != B_OK) {
2087 		TRACE("fRawAudioQueue->Remove failed, error %lx\n", err);
2088 		fCurrentAudioPacket = 0;
2089 		return B_ERROR;
2090 	}
2091 
2092 	const uint8 *data;
2093 	size_t size;
2094 
2095 	if (B_OK != pes_extract(fCurrentAudioPacket->Data(),
2096 			fCurrentAudioPacket->Size(), &data, &size)) {
2097 		TRACE("audio pes_extract failed\n");
2098 		return B_ERROR;
2099 	}
2100 
2101 	*chunkData = data;
2102 	*chunkLen = size;
2103 	// measured in PCR time base
2104 	mh->start_time = fCurrentAudioPacket->TimeStamp();
2105 
2106 //	printf("GetNextAudioChunk: done start_time %Ld\n", mh->start_time);
2107 
2108 	return B_OK;
2109 }
2110 
2111 
2112 status_t
2113 DVBMediaNode::_GetNextVideoChunk(const void **chunkData, size_t *chunkLen,
2114 	media_header *mh, void *cookie)
2115 {
2116 	return static_cast<DVBMediaNode *>(cookie)->GetNextVideoChunk(chunkData,
2117 		chunkLen, mh);
2118 }
2119 
2120 
2121 status_t
2122 DVBMediaNode::_GetNextAudioChunk(const void **chunkData, size_t *chunkLen,
2123 	media_header *mh, void *cookie)
2124 {
2125 	return static_cast<DVBMediaNode *>(cookie)->GetNextAudioChunk(chunkData,
2126 		chunkLen, mh);
2127 }
2128 
2129 
2130 status_t
2131 DVBMediaNode::GetStreamFormat(PacketQueue *queue, media_format *format)
2132 {
2133 	status_t status;
2134 	Packet *packet;
2135 	const uint8 *data;
2136 	size_t size;
2137 	int stream_id;
2138 
2139 	// get copy of the first packet from queue, and determine format
2140 	status = queue->Peek(&packet);
2141 	if (status != B_OK) {
2142 		TRACE("queue->Peek failed, error %lx\n", status);
2143 		return status;
2144 	}
2145 	status = pes_extract(packet->Data(), packet->Size(), &data, &size);
2146 	if (status != B_OK) {
2147 		TRACE("pes_extract failed\n");
2148 		goto done;
2149 	}
2150 	status = pes_stream_id(packet->Data(), packet->Size(), &stream_id);
2151 	if (status != B_OK) {
2152 		TRACE("pes_stream_id failed\n");
2153 		goto done;
2154 	}
2155 	status = GetHeaderFormat(format, data, size, stream_id);
2156 	if (status != B_OK) {
2157 		TRACE("GetHeaderFormat failed, error %lx\n", status);
2158 		goto done;
2159 	}
2160 
2161 done:
2162 	delete packet;
2163 	return status;
2164 }
2165 
2166 
2167 enum {
2168 	ID_STATE	= 11,
2169 	ID_REGION	= 12,
2170 	ID_CHANNEL	= 13,
2171 	ID_AUDIO	= 14,
2172 };
2173 
2174 
2175 void
2176 DVBMediaNode::RefreshParameterWeb()
2177 {
2178 	TRACE("DVBMediaNode::RefreshParameterWeb enter\n");
2179 	fWeb = CreateParameterWeb();
2180 	SetParameterWeb(fWeb);
2181 	TRACE("DVBMediaNode::RefreshParameterWeb finished\n");
2182 }
2183 
2184 
2185 void
2186 DVBMediaNode::SetAboutInfo(BParameterGroup *about)
2187 {
2188 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "DVB media_addon info:",
2189 		B_GENERIC);
2190 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Version " VERSION,
2191 		B_GENERIC);
2192 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Revision " REVISION,
2193 		B_GENERIC);
2194 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Build " BUILD, B_GENERIC);
2195 
2196 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "", B_GENERIC);
2197 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Driver info:", B_GENERIC);
2198 
2199 	dvb_type_t type;
2200 	char name[200];
2201 	char info[200];
2202 
2203 	fCard->GetCardType(&type);
2204 	fCard->GetCardInfo(name, sizeof(name), info, sizeof(info));
2205 
2206 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, name, B_GENERIC);
2207 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, info, B_GENERIC);
2208 }
2209 
2210 
2211 BParameterWeb *
2212 DVBMediaNode::CreateParameterWeb()
2213 {
2214 	/* Set up the parameter web */
2215 	BParameterWeb *web = new BParameterWeb();
2216 
2217 	char n[200], i[200];
2218 	fCard->GetCardInfo(n, sizeof(n), i, sizeof(i));
2219 
2220 	BString name;
2221 	name << Name() << " - " << i;
2222 
2223 	BParameterGroup *main = web->MakeGroup(name.String());
2224 
2225 	BParameterGroup *ctrl = main->MakeGroup("Channel Selection");
2226 	ctrl->MakeNullParameter(0, B_MEDIA_NO_TYPE, ctrl->Name(), B_GENERIC);
2227 
2228 	BParameterGroup *pref = main->MakeGroup("Preferences");
2229 	pref->MakeNullParameter(0, B_MEDIA_NO_TYPE, pref->Name(), B_GENERIC);
2230 
2231 	BDiscreteParameter *state = pref->MakeDiscreteParameter(
2232 			ID_STATE, B_MEDIA_RAW_VIDEO, "State", B_GENERIC);
2233 
2234 	BDiscreteParameter *region = pref->MakeDiscreteParameter(
2235 			ID_REGION, B_MEDIA_RAW_VIDEO, "Region", B_GENERIC);
2236 
2237 	BDiscreteParameter *chan = ctrl->MakeDiscreteParameter(
2238 			ID_CHANNEL, B_MEDIA_RAW_VIDEO, "Channel",
2239 			/* B_TUNER_CHANNEL */ B_GENERIC);
2240 
2241 	BDiscreteParameter *aud = ctrl->MakeDiscreteParameter(
2242 			ID_AUDIO, B_MEDIA_RAW_VIDEO, "Audio", B_GENERIC);
2243 
2244 	AddStateItems(state);
2245 	AddRegionItems(region);
2246 	AddChannelItems(chan);
2247 	AddAudioItems(aud);
2248 
2249 
2250 	if (!fTuningSuccess || !fCaptureActive) {
2251 		BParameterGroup *info = main->MakeGroup("Info");
2252 		info->MakeNullParameter(0, B_MEDIA_NO_TYPE, info->Name(), B_GENERIC);
2253 		BParameterGroup *about = main->MakeGroup("About");
2254 		about->MakeNullParameter(0, B_MEDIA_NO_TYPE, about->Name(), B_GENERIC);
2255 		SetAboutInfo(about);
2256 //		info->MakeNullParameter(0, B_MEDIA_NO_TYPE,
2257 //			fCaptureActive ? "Tuning failed" : "Node stopped", B_GENERIC);
2258 		info->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Node is stopped",
2259 			B_GENERIC);
2260 		info->MakeNullParameter(0, B_MEDIA_NO_TYPE, "or tuning failed.",
2261 			B_GENERIC);
2262 		return web;
2263 	}
2264 
2265 	BParameterGroup *info1 = main->MakeGroup("Info");
2266 	info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, info1->Name(), B_GENERIC);
2267 	BParameterGroup *info2 = main->MakeGroup("Info");
2268 	info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, info2->Name(), B_GENERIC);
2269 	BParameterGroup *about = main->MakeGroup("About");
2270 	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, about->Name(), B_GENERIC);
2271 	SetAboutInfo(about);
2272 
2273 	BString sInterfaceType = "Interface Type: ";
2274 	BString sFrequency = "Frequency: ";
2275 	BString sAudioPid = "Audio PID: ";
2276 	BString sVideoPid = "Video PID: ";
2277 	BString sPcrPid = "PCR PID: ";
2278 	BString sInversion = "Inversion: ";
2279 	BString sBandwidth = "Bandwith: ";
2280 	BString sModulation = "Modulation: ";
2281 	BString sHierarchy = "Hierarchy: ";
2282 	BString sCodeRateHP = "Code Rate HP: ";
2283 	BString sCodeRateLP = "Code Rate LP: ";
2284 	BString sTransmissionMode = "Transmission Mode: ";
2285 	BString sGuardInterval = "Guard Interval: ";
2286 
2287 	BString sSymbolRate = "Symbol Rate: ";
2288 	BString sPolarity = "Polarity: ";
2289 	BString sAgcInversion = "AGC Inversion: ";
2290 
2291 	switch (fInterfaceType) {
2292 		case DVB_TYPE_DVB_C:
2293 			sInterfaceType << "DVB-C";
2294 			break;
2295 
2296 		case DVB_TYPE_DVB_H:
2297 			sInterfaceType << "DVB-H";
2298 			break;
2299 
2300 		case DVB_TYPE_DVB_S:
2301 			sInterfaceType << "DVB-S";
2302 			break;
2303 
2304 		case DVB_TYPE_DVB_T:
2305 			sInterfaceType << "DVB-T";
2306 			break;
2307 
2308 		default:
2309 			sInterfaceType << "unknown";
2310 			break;
2311 	}
2312 
2313 	sAudioPid << fAudioPid;
2314 	sVideoPid << fVideoPid;
2315 	sPcrPid << fPcrPid;
2316 
2317 	if (fInterfaceType == DVB_TYPE_DVB_T) {
2318 
2319 		sFrequency << fTuningParam.u.dvb_t.frequency / 1000000 << " MHz";
2320 
2321 		switch (fTuningParam.u.dvb_t.inversion) {
2322 			case DVB_INVERSION_AUTO:
2323 				sInversion << "auto";
2324 				break;
2325 
2326 			case DVB_INVERSION_ON:
2327 				sInversion << "on";
2328 				break;
2329 
2330 			case DVB_INVERSION_OFF:
2331 				sInversion << "off";
2332 				break;
2333 
2334 			default:
2335 				sInversion << "unknown";
2336 				break;
2337 		}
2338 
2339 		switch (fTuningParam.u.dvb_t.bandwidth) {
2340 			case DVB_BANDWIDTH_AUTO:
2341 				sBandwidth << "auto";
2342 				break;
2343 
2344 			case DVB_BANDWIDTH_6_MHZ:
2345 				sBandwidth << "6 MHz";
2346 				break;
2347 
2348 			case DVB_BANDWIDTH_7_MHZ:
2349 				sBandwidth << "7 MHz";
2350 				break;
2351 
2352 			case DVB_BANDWIDTH_8_MHZ:
2353 				sBandwidth << "8 MHz";
2354 				break;
2355 
2356 			default:
2357 				sBandwidth << "unknown";
2358 				break;
2359 		}
2360 
2361 		switch (fTuningParam.u.dvb_t.modulation) {
2362 			case DVB_MODULATION_AUTO:
2363 				sModulation << "auto";
2364 				break;
2365 
2366 			case DVB_MODULATION_QPSK:
2367 				sModulation << "QPSK";
2368 				break;
2369 
2370 			case DVB_MODULATION_16_QAM:
2371 				sModulation << "16 QAM";
2372 				break;
2373 
2374 			case DVB_MODULATION_32_QAM:
2375 				sModulation << "32 QAM";
2376 				break;
2377 
2378 			case DVB_MODULATION_64_QAM:
2379 				sModulation << "64 QAM";
2380 				break;
2381 
2382 			case DVB_MODULATION_128_QAM:
2383 				sModulation << "128 QAM";
2384 				break;
2385 
2386 			case DVB_MODULATION_256_QAM:
2387 				sModulation << "256 QAM";
2388 				break;
2389 
2390 			default:
2391 				sModulation << "unknown";
2392 				break;
2393 		}
2394 
2395 		switch (fTuningParam.u.dvb_t.hierarchy) {
2396 			case DVB_HIERARCHY_AUTO:
2397 				sHierarchy << "auto";
2398 				break;
2399 
2400 			case DVB_HIERARCHY_NONE:
2401 				sHierarchy << "none";
2402 				break;
2403 
2404 			case DVB_HIERARCHY_1:
2405 				sHierarchy << "1";
2406 				break;
2407 
2408 			case DVB_HIERARCHY_2:
2409 				sHierarchy << "2";
2410 				break;
2411 
2412 			case DVB_HIERARCHY_4:
2413 				sHierarchy << "4";
2414 				break;
2415 
2416 			default:
2417 				sHierarchy << "unknown";
2418 				break;
2419 		}
2420 
2421 		switch (fTuningParam.u.dvb_t.code_rate_hp) {
2422 			case DVB_FEC_AUTO:
2423 				sCodeRateHP << "auto";
2424 				break;
2425 
2426 			case DVB_FEC_NONE:
2427 				sCodeRateHP << "none";
2428 				break;
2429 
2430 			case DVB_FEC_1_2:
2431 				sCodeRateHP << "FEC 1/2";
2432 				break;
2433 
2434 			case DVB_FEC_2_3:
2435 				sCodeRateHP << "FEC 2/3";
2436 				break;
2437 
2438 			case DVB_FEC_3_4:
2439 				sCodeRateHP << "FEC 3/4";
2440 				break;
2441 
2442 			case DVB_FEC_4_5:
2443 				sCodeRateHP << "FEC 4/5";
2444 				break;
2445 
2446 			case DVB_FEC_5_6:
2447 				sCodeRateHP << "FEC 5/6";
2448 				break;
2449 
2450 			case DVB_FEC_6_7:
2451 				sCodeRateHP << "FEC 6/7";
2452 				break;
2453 
2454 			case DVB_FEC_7_8:
2455 				sCodeRateHP << "FEC 7/8";
2456 				break;
2457 
2458 			case DVB_FEC_8_9:
2459 				sCodeRateHP << "FEC 8/9";
2460 				break;
2461 
2462 			default:
2463 				sCodeRateHP << "unknown";
2464 				break;
2465 		}
2466 
2467 		switch (fTuningParam.u.dvb_t.code_rate_lp) {
2468 			case DVB_FEC_AUTO:
2469 				sCodeRateLP << "auto";
2470 				break;
2471 
2472 			case DVB_FEC_NONE:
2473 				sCodeRateLP << "none";
2474 				break;
2475 
2476 			case DVB_FEC_1_2:
2477 				sCodeRateLP << "FEC 1/2";
2478 				break;
2479 
2480 			case DVB_FEC_2_3:
2481 				sCodeRateLP << "FEC 2/3";
2482 				break;
2483 
2484 			case DVB_FEC_3_4:
2485 				sCodeRateLP << "FEC 3/4";
2486 				break;
2487 
2488 			case DVB_FEC_4_5:
2489 				sCodeRateLP << "FEC 4/5";
2490 				break;
2491 
2492 			case DVB_FEC_5_6:
2493 				sCodeRateLP << "FEC 5/6";
2494 				break;
2495 
2496 			case DVB_FEC_6_7:
2497 				sCodeRateLP << "FEC 6/7";
2498 				break;
2499 
2500 			case DVB_FEC_7_8:
2501 				sCodeRateLP << "FEC 7/8";
2502 				break;
2503 
2504 			case DVB_FEC_8_9:
2505 				sCodeRateLP << "FEC 8/9";
2506 				break;
2507 
2508 			default:
2509 				sCodeRateLP << "unknown";
2510 				break;
2511 		}
2512 
2513 		switch (fTuningParam.u.dvb_t.transmission_mode) {
2514 			case DVB_TRANSMISSION_MODE_AUTO:
2515 				sTransmissionMode << "auto";
2516 				break;
2517 
2518 			case DVB_TRANSMISSION_MODE_2K:
2519 				sTransmissionMode << "2K";
2520 				break;
2521 
2522 			case DVB_TRANSMISSION_MODE_4K:
2523 				sTransmissionMode << "4K";
2524 				break;
2525 
2526 			case DVB_TRANSMISSION_MODE_8K:
2527 				sTransmissionMode << "8K";
2528 				break;
2529 
2530 			default:
2531 				sTransmissionMode << "unknown";
2532 				break;
2533 		}
2534 
2535 		switch (fTuningParam.u.dvb_t.guard_interval) {
2536 			case DVB_GUARD_INTERVAL_AUTO:
2537 				sGuardInterval << "auto";
2538 				break;
2539 
2540 			case DVB_GUARD_INTERVAL_1_4:
2541 				sGuardInterval << "1/4";
2542 				break;
2543 
2544 			case DVB_GUARD_INTERVAL_1_8:
2545 				sGuardInterval << "1/8";
2546 				break;
2547 
2548 			case DVB_GUARD_INTERVAL_1_16:
2549 				sGuardInterval << "1/16";
2550 				break;
2551 
2552 			case DVB_GUARD_INTERVAL_1_32:
2553 				sGuardInterval << "1/32";
2554 				break;
2555 
2556 			default:
2557 				sGuardInterval << "unknown";
2558 				break;
2559 		}
2560 
2561 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInterfaceType.String(),
2562 			B_GENERIC);
2563 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sFrequency.String(),
2564 			B_GENERIC);
2565 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sBandwidth.String(),
2566 			B_GENERIC);
2567 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sVideoPid.String(),
2568 			B_GENERIC);
2569 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sAudioPid.String(),
2570 			B_GENERIC);
2571 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sPcrPid.String(),
2572 			B_GENERIC);
2573 
2574 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sModulation.String(),
2575 			B_GENERIC);
2576 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE,
2577 			sTransmissionMode.String(), B_GENERIC);
2578 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sGuardInterval.String(),
2579 			B_GENERIC);
2580 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sCodeRateHP.String(),
2581 			B_GENERIC);
2582 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sCodeRateLP.String(),
2583 			B_GENERIC);
2584 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInversion.String(),
2585 			B_GENERIC);
2586 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sHierarchy.String(),
2587 			B_GENERIC);
2588 	}
2589 
2590 	if (fInterfaceType == DVB_TYPE_DVB_S) {
2591 
2592 		sFrequency << fTuningParam.u.dvb_s.frequency / 1000000 << " MHz";
2593 		sSymbolRate << fTuningParam.u.dvb_s.symbolrate;
2594 
2595 		switch (fTuningParam.u.dvb_s.inversion) {
2596 			case DVB_INVERSION_AUTO:
2597 				sInversion << "auto";
2598 				break;
2599 
2600 			case DVB_INVERSION_ON:
2601 				sInversion << "on";
2602 				break;
2603 
2604 			case DVB_INVERSION_OFF:
2605 				sInversion << "off";
2606 				break;
2607 
2608 			default:
2609 				sInversion << "unknown";
2610 				break;
2611 		}
2612 
2613 		switch (fTuningParam.u.dvb_s.polarity) {
2614 			case DVB_POLARITY_VERTICAL:
2615 				sPolarity << "vertical";
2616 				break;
2617 
2618 			case DVB_POLARITY_HORIZONTAL:
2619 				sPolarity << "horizontal";
2620 				break;
2621 
2622 			default:
2623 				sPolarity << "unknown";
2624 				break;
2625 		}
2626 
2627 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInterfaceType.String(),
2628 			B_GENERIC);
2629 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sVideoPid.String(),
2630 			B_GENERIC);
2631 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sAudioPid.String(),
2632 			B_GENERIC);
2633 		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sPcrPid.String(),
2634 			B_GENERIC);
2635 
2636 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sFrequency.String(),
2637 			B_GENERIC);
2638 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sPolarity.String(),
2639 			B_GENERIC);
2640 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sSymbolRate.String(),
2641 			B_GENERIC);
2642 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInversion.String(),
2643 			B_GENERIC);
2644 		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sAgcInversion.String(),
2645 			B_GENERIC);
2646 	}
2647 
2648 	return web;
2649 }
2650 
2651 
2652 void
2653 DVBMediaNode::LoadSettings()
2654 {
2655 	TRACE("DVBMediaNode::LoadSettings\n");
2656 	RefreshStateList();
2657 	fSelectedState = 0;
2658 	RefreshRegionList();
2659 	fSelectedRegion = 0;
2660 	RefreshChannelList();
2661 	fSelectedChannel = 0;
2662 	RefreshAudioList();
2663 	fSelectedAudio = 0;
2664 }
2665 
2666 
2667 void
2668 DVBMediaNode::RefreshStateList()
2669 {
2670 	TRACE("DVBMediaNode::RefreshStateList\n");
2671 
2672 	fStateList->MakeEmpty();
2673 	fSelectedState = -1;
2674 
2675 	const char *dir;
2676 	switch (fInterfaceType) {
2677 		case DVB_TYPE_DVB_C:
2678 			dir = "/boot/home/config/settings/Media/dvb/dvb-c channels";
2679 			break;
2680 
2681 		case DVB_TYPE_DVB_H:
2682 			dir = "/boot/home/config/settings/Media/dvb/dvb-h channels";
2683 			break;
2684 
2685 		case DVB_TYPE_DVB_S:
2686 			dir = "/boot/home/config/settings/Media/dvb/dvb-s channels";
2687 			break;
2688 
2689 		case DVB_TYPE_DVB_T:
2690 			dir = "/boot/home/config/settings/Media/dvb/dvb-t channels";
2691 			break;
2692 
2693 		default:
2694 			printf("DVBMediaNode::RefreshStateList unknown interface type\n");
2695 			return;
2696 	}
2697 
2698 	TRACE("loading channel lists from dir = %s\n", dir);
2699 
2700 	BDirectory d(dir);
2701 	BEntry e;
2702 	BPath p;
2703 	while (B_OK == d.GetNextEntry(&e, false)) {
2704 		if (B_OK != e.GetPath(&p))
2705 			continue;
2706 		fStateList->AddItem(p.Path());
2707 	}
2708 
2709 	if (fStateList->ItemAt(0))
2710 		fSelectedState = 0;
2711 }
2712 
2713 
2714 void
2715 DVBMediaNode::RefreshRegionList()
2716 {
2717 	TRACE("DVBMediaNode::RefreshRegionList\n");
2718 
2719 	fRegionList->MakeEmpty();
2720 	fSelectedRegion = -1;
2721 
2722 	const char *dir = fStateList->ItemAt(fSelectedState);
2723 	if (!dir)
2724 		return;
2725 
2726 	BDirectory d(dir);
2727 	BEntry e;
2728 	BPath p;
2729 	while (B_OK == d.GetNextEntry(&e, false)) {
2730 		if (B_OK != e.GetPath(&p))
2731 			continue;
2732 		fRegionList->AddItem(p.Path());
2733 	}
2734 
2735 	if (fRegionList->ItemAt(0))
2736 		fSelectedRegion = 0;
2737 }
2738 
2739 
2740 void
2741 DVBMediaNode::RefreshChannelList()
2742 {
2743 	TRACE("DVBMediaNode::RefreshChannelList\n");
2744 
2745 	fChannelList->MakeEmpty();
2746 	fSelectedChannel = -1;
2747 
2748 	const char *path = fRegionList->ItemAt(fSelectedRegion);
2749 	if (!path)
2750 		return;
2751 
2752 	TRACE("opening channel list file = %s\n", path);
2753 
2754 	FILE *f = fopen(path, "r");
2755 	if (!f)
2756 		return;
2757 
2758 	char line[1024];
2759 	while (fgets(line, sizeof(line), f)) {
2760 		if (line[0] == ':') // skip comments
2761 			continue;
2762 		if (strchr(line, ':') == NULL)	// skip empty lines
2763 			continue;
2764 		fChannelList->AddItem(line);
2765 	}
2766 
2767 	fclose(f);
2768 
2769 	if (fChannelList->ItemAt(0))
2770 		fSelectedChannel = 0;
2771 }
2772 
2773 
2774 void
2775 DVBMediaNode::RefreshAudioList()
2776 {
2777 	TRACE("DVBMediaNode::RefreshAudioList\n");
2778 
2779 	fAudioList->MakeEmpty();
2780 	fSelectedAudio = -1;
2781 
2782 	fAudioList->AddItem("default"); // XXX test
2783 
2784 	if (fAudioList->ItemAt(0))
2785 		fSelectedAudio = 0;
2786 }
2787 
2788 
2789 void
2790 DVBMediaNode::AddStateItems(BDiscreteParameter *param)
2791 {
2792 	TRACE("DVBMediaNode::AddStateItems\n");
2793 
2794 	const char *str;
2795 	for (int i = 0; (str = fStateList->ItemAt(i)); i++) {
2796 		str = strrchr(str, '/');
2797 		if (!str)
2798 			continue;
2799 		str++;
2800 		param->AddItem(i, str);
2801 	}
2802 	if (param->CountItems() == 0)
2803 		param->AddItem(-1, "none");
2804 }
2805 
2806 
2807 void
2808 DVBMediaNode::AddRegionItems(BDiscreteParameter *param)
2809 {
2810 	TRACE("DVBMediaNode::AddRegionItems\n");
2811 
2812 	const char *str;
2813 	for (int i = 0; (str = fRegionList->ItemAt(i)); i++) {
2814 		str = strrchr(str, '/');
2815 		if (!str)
2816 			continue;
2817 		str++;
2818 		param->AddItem(i, str);
2819 	}
2820 	if (param->CountItems() == 0)
2821 		param->AddItem(-1, "none");
2822 }
2823 
2824 
2825 void
2826 DVBMediaNode::AddChannelItems(BDiscreteParameter *param)
2827 {
2828 	TRACE("DVBMediaNode::AddChannelItems\n");
2829 
2830 	const char *str;
2831 	for (int i = 0; (str = fChannelList->ItemAt(i)); i++) {
2832 		char name[256];
2833 //		sscanf(str, "%s:", name);
2834 		sscanf(str, "%[^:]", name);
2835 		param->AddItem(i, name);
2836 
2837 	}
2838 	if (param->CountItems() == 0)
2839 		param->AddItem(-1, "none");
2840 }
2841 
2842 
2843 void
2844 DVBMediaNode::AddAudioItems(BDiscreteParameter *param)
2845 {
2846 	TRACE("DVBMediaNode::AddAudioItems\n");
2847 
2848 	if (param->CountItems() == 0)
2849 		param->AddItem(-1, "default");
2850 }
2851 
2852 
2853 status_t
2854 DVBMediaNode::GetParameterValue(int32 id, bigtime_t *last_change, void *value,
2855 	size_t *size)
2856 {
2857 //	TRACE("DVBMediaNode::GetParameterValue, id 0x%lx\n", id);
2858 
2859 	switch (id) {
2860 		case ID_STATE:
2861 			*size = 4;
2862 			*(int32 *)value = fSelectedState;
2863 			break;
2864 
2865 		case ID_REGION:
2866 			*size = 4;
2867 			*(int32 *)value = fSelectedRegion;
2868 			break;
2869 
2870 		case ID_CHANNEL:
2871 			*size = 4;
2872 			*(int32 *)value = fSelectedChannel;
2873 			break;
2874 
2875 		case ID_AUDIO:
2876 			*size = 4;
2877 			*(int32 *)value = fSelectedAudio;
2878 			break;
2879 
2880 		default:
2881 			return B_ERROR;
2882 	}
2883 	return B_OK;
2884 }
2885 
2886 
2887 void
2888 DVBMediaNode::SetParameterValue(int32 id, bigtime_t when, const void *value,
2889 	size_t size)
2890 {
2891 	TRACE("DVBMediaNode::SetParameterValue, id 0x%lx, size %ld, value 0x%lx\n",
2892 		id, size, *(const int32 *)value);
2893 
2894 	switch (id) {
2895 		case ID_STATE:
2896 			fSelectedState = *(const int32 *)value;
2897 			StopCapture();
2898 			RefreshRegionList();
2899 			RefreshChannelList();
2900 			RefreshAudioList();
2901 			EventQueue()->AddEvent(media_timed_event(0,
2902 				M_REFRESH_PARAMETER_WEB));
2903 //			Tune();
2904 			break;
2905 
2906 		case ID_REGION:
2907 			fSelectedRegion = *(const int32 *)value;
2908 			StopCapture();
2909 			RefreshChannelList();
2910 			RefreshAudioList();
2911 			EventQueue()->AddEvent(media_timed_event(0,
2912 				M_REFRESH_PARAMETER_WEB));
2913 //			Tune();
2914 			break;
2915 
2916 		case ID_CHANNEL:
2917 			fSelectedChannel = *(const int32 *)value;
2918 			RefreshAudioList();
2919 //			EventQueue()->AddEvent(media_timed_event(0,
2920 //				M_REFRESH_PARAMETER_WEB));
2921 			Tune();
2922 			break;
2923 
2924 		case ID_AUDIO:
2925 			fSelectedAudio = *(const int32 *)value;
2926 			Tune();
2927 			break;
2928 
2929 		default:
2930 			break;
2931 	}
2932 	TRACE("DVBMediaNode::SetParameterValue finished\n");
2933 }
2934 
2935 
2936 status_t
2937 DVBMediaNode::ExtractTuningParams(const char *description, int audio_pid_index,
2938 	dvb_tuning_parameters_t *tuning_param, int *video_pid, int *audio_pid,
2939 	int *pcr_pid)
2940 {
2941 	if (!description)
2942 		return B_ERROR;
2943 
2944 	printf("ExtractTuningParams: \"%s\"\n", description);
2945 
2946 	char name[50];
2947 	char freq[50];
2948 	char para[100];
2949 	char src[50];
2950 	char srate[50];
2951 	char vpid[50];
2952 	char apid[50];
2953 	char tpid[50];
2954 	char ca[50];
2955 	char sid[50];
2956 	char nid[50];
2957 	char tid[50];
2958 	char rid[50];
2959 
2960 	sscanf(description, " %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:]"
2961 		" : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] ", name, freq, para,
2962 		src, srate, vpid, apid, tpid, ca, sid, nid, tid, rid);
2963 
2964 	char *cpid = strchr(vpid, '+');
2965 	if (cpid) cpid++;
2966 
2967 	int _vpid = strtol(vpid, 0, 0);
2968 	int _apid = strtol(apid, 0, 0);
2969 //	int _tpid = strtol(tpid, 0, 0);
2970 	int _cpid = cpid ? strtol(cpid, 0, 0) : _vpid;
2971 	int _srate = strtol(srate, 0, 0);
2972 	int64 _freq = strtol(freq, 0, 0);
2973 	while (_freq && _freq <= 1000000)
2974 		_freq *= 1000;
2975 
2976 	if (fInterfaceType == DVB_TYPE_DVB_S && _freq < 950000000) {
2977 		TRACE("workaround activated: type is DVB_S and frequency < 950 MHz,"
2978 			" multiplying by 1000!\n");
2979 		_freq *= 1000;
2980 	}
2981 
2982 
2983 	*video_pid = _vpid;
2984 	*audio_pid = _apid;
2985 	*pcr_pid   = _cpid;
2986 
2987 	TRACE("parsing result: params: '%s'\n", para);
2988 
2989 	TRACE("parsing result: video pid %d\n", _vpid);
2990 	TRACE("parsing result: audio pid %d\n", _apid);
2991 	TRACE("parsing result: PCR pid %d\n", _cpid);
2992 	TRACE("parsing result: symbol rate %d\n", _srate);
2993 	TRACE("parsing result: Frequency %Ld Hz, %Ld MHz\n", _freq, _freq / 1000000);
2994 
2995 	if (fInterfaceType == DVB_TYPE_DVB_T) {
2996 
2997 		dvb_t_tuning_parameters_t *param = &tuning_param->u.dvb_t;
2998 
2999 		TRACE("Interface is DVB-T\n");
3000 		param->frequency = _freq;
3001 		param->inversion = DVB_INVERSION_OFF;
3002 		param->bandwidth = DVB_BANDWIDTH_8_MHZ;
3003 		param->modulation = DVB_MODULATION_16_QAM;
3004 		param->hierarchy = DVB_HIERARCHY_NONE;
3005 		param->code_rate_hp = DVB_FEC_2_3;
3006 		param->code_rate_lp = DVB_FEC_2_3;
3007 		param->transmission_mode = DVB_TRANSMISSION_MODE_8K;
3008 		param->guard_interval = DVB_GUARD_INTERVAL_1_4;
3009 	}
3010 
3011 	if (fInterfaceType == DVB_TYPE_DVB_S) {
3012 		dvb_s_tuning_parameters_t *param = &tuning_param->u.dvb_s;
3013 
3014 		TRACE("Interface is DVB-S\n");
3015 
3016 		const char *pInv = strchr(para, 'I');
3017 		if (pInv == NULL)
3018 			pInv = strchr(para, 'i');
3019 		if (pInv != NULL && pInv[1] == '0') {
3020 			TRACE("DVB_INVERSION_OFF\n");
3021 			param->inversion = DVB_INVERSION_OFF;
3022 		} else if (pInv != NULL && pInv[1] == '1') {
3023 			TRACE("DVB_INVERSION_ON\n");
3024 			param->inversion = DVB_INVERSION_ON;
3025 		} else {
3026 			TRACE("parse error, assuming DVB_INVERSION_OFF\n");
3027 			param->inversion = DVB_INVERSION_OFF;
3028 		}
3029 
3030 		const char *pPolH = strchr(para, 'H');
3031 		if (pPolH == NULL)
3032 			pPolH = strchr(para, 'h');
3033 		const char *pPolV = strchr(para, 'V');
3034 		if (pPolV == NULL)
3035 			pPolV = strchr(para, 'v');
3036 		if (pPolH != NULL && pPolV == NULL) {
3037 			TRACE("DVB_POLARITY_HORIZONTAL\n");
3038 			param->polarity = DVB_POLARITY_HORIZONTAL;
3039 		} else if (pPolH == NULL && pPolV != NULL) {
3040 			TRACE("DVB_POLARITY_VERTICAL\n");
3041 			param->polarity = DVB_POLARITY_VERTICAL;
3042 		} else {
3043 			TRACE("parse error, assuming DVB_POLARITY_HORIZONTAL\n");
3044 			param->polarity = DVB_POLARITY_HORIZONTAL;
3045 		}
3046 
3047 		param->frequency = _freq;
3048 		param->symbolrate = _srate;
3049 	}
3050 
3051 	return B_OK;
3052 }
3053