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
112DVBMediaNode::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
202DVBMediaNode::~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
248BMediaAddOn *
249DVBMediaNode::AddOn(int32 *internal_id) const
250{
251	if (internal_id)
252		*internal_id = fInternalID;
253	return fAddOn;
254}
255
256
257status_t
258DVBMediaNode::HandleMessage(int32 message, const void *data, size_t size)
259{
260	return B_ERROR;
261}
262
263
264void
265DVBMediaNode::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
272void
273DVBMediaNode::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
281void
282DVBMediaNode::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
293void
294DVBMediaNode::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
355void
356DVBMediaNode::Stop(bigtime_t performance_time, bool immediate)
357{
358	if (fStopDisabled)
359		return;
360	else
361		BMediaEventLooper::Stop(performance_time, immediate);
362}
363
364
365void
366DVBMediaNode::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
401status_t
402DVBMediaNode::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
412status_t
413DVBMediaNode::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
429status_t
430DVBMediaNode::DisposeOutputCookie(int32 cookie)
431{
432	return B_OK;
433}
434
435
436status_t
437DVBMediaNode::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
445status_t
446DVBMediaNode::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
454status_t
455DVBMediaNode::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
466status_t
467DVBMediaNode::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
507status_t
508DVBMediaNode::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
646status_t
647DVBMediaNode::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
780void
781DVBMediaNode::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
853void
854DVBMediaNode::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
890void
891DVBMediaNode::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
899void
900DVBMediaNode::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
918status_t
919DVBMediaNode::SetPlayRate(int32 numer, int32 denom)
920{
921
922	return B_ERROR;
923}
924
925
926void
927DVBMediaNode::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
936void
937DVBMediaNode::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
947void
948DVBMediaNode::HandleTimeWarp(bigtime_t performance_time)
949{
950	TRACE("DVBMediaNode::HandleTimeWarp at %Ld\n", performance_time);
951}
952
953
954void
955DVBMediaNode::HandleSeek(bigtime_t performance_time)
956{
957	TRACE("DVBMediaNode::HandleSeek at %Ld\n", performance_time);
958}
959
960
961void
962DVBMediaNode::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
1008bool
1009DVBMediaNode::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
1020bool
1021DVBMediaNode::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
1032void
1033DVBMediaNode::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
1044void
1045DVBMediaNode::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
1059void
1060DVBMediaNode::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
1067void
1068DVBMediaNode::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
1075void
1076DVBMediaNode::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
1083status_t
1084DVBMediaNode::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
1120status_t
1121DVBMediaNode::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
1156const char *
1157DVBMediaNode::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
1181void
1182DVBMediaNode::HandleStart(bigtime_t performance_time)
1183{
1184	TRACE("DVBMediaNode::HandleStart\n");
1185	StartCapture();
1186}
1187
1188
1189void
1190DVBMediaNode::HandleStop(void)
1191{
1192	TRACE("DVBMediaNode::HandleStop\n");
1193	StopCapture();
1194}
1195
1196
1197status_t
1198DVBMediaNode::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) {
1268printf("about to stop capture 1\n");
1269#if STOP_CAPTURE_WHILE_TUNING
1270printf("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
1301end:
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
1310status_t
1311DVBMediaNode::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
1336status_t
1337DVBMediaNode::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
1352status_t
1353DVBMediaNode::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
1389status_t
1390DVBMediaNode::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
1427int32
1428DVBMediaNode::_card_reader_thread_(void *arg)
1429{
1430	static_cast<DVBMediaNode *>(arg)->card_reader_thread();
1431	return 0;
1432}
1433
1434
1435int32
1436DVBMediaNode::_mpeg_demux_thread_(void *arg)
1437{
1438	static_cast<DVBMediaNode *>(arg)->mpeg_demux_thread();
1439	return 0;
1440}
1441
1442
1443int32
1444DVBMediaNode::_raw_audio_thread_(void *arg)
1445{
1446	static_cast<DVBMediaNode *>(arg)->raw_audio_thread();
1447	return 0;
1448}
1449
1450
1451int32
1452DVBMediaNode::_raw_video_thread_(void *arg)
1453{
1454	static_cast<DVBMediaNode *>(arg)->raw_video_thread();
1455	return 0;
1456}
1457
1458
1459int32
1460DVBMediaNode::_enc_audio_thread_(void *arg)
1461{
1462	static_cast<DVBMediaNode *>(arg)->enc_audio_thread();
1463	return 0;
1464}
1465
1466
1467int32
1468DVBMediaNode::_enc_video_thread_(void *arg)
1469{
1470	static_cast<DVBMediaNode *>(arg)->enc_video_thread();
1471	return 0;
1472}
1473
1474
1475int32
1476DVBMediaNode::_mpeg_ts_thread_(void *arg)
1477{
1478	static_cast<DVBMediaNode *>(arg)->mpeg_ts_thread();
1479	return 0;
1480}
1481
1482
1483void
1484DVBMediaNode::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
1512void
1513DVBMediaNode::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
1530void
1531DVBMediaNode::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
1556void
1557DVBMediaNode::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
1597void
1598DVBMediaNode::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
1639void
1640DVBMediaNode::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
1828void
1829DVBMediaNode::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
2042inline status_t
2043DVBMediaNode::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
2076inline status_t
2077DVBMediaNode::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
2112status_t
2113DVBMediaNode::_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
2121status_t
2122DVBMediaNode::_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
2130status_t
2131DVBMediaNode::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
2161done:
2162	delete packet;
2163	return status;
2164}
2165
2166
2167enum {
2168	ID_STATE	= 11,
2169	ID_REGION	= 12,
2170	ID_CHANNEL	= 13,
2171	ID_AUDIO	= 14,
2172};
2173
2174
2175void
2176DVBMediaNode::RefreshParameterWeb()
2177{
2178	TRACE("DVBMediaNode::RefreshParameterWeb enter\n");
2179	fWeb = CreateParameterWeb();
2180	SetParameterWeb(fWeb);
2181	TRACE("DVBMediaNode::RefreshParameterWeb finished\n");
2182}
2183
2184
2185void
2186DVBMediaNode::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
2211BParameterWeb *
2212DVBMediaNode::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
2652void
2653DVBMediaNode::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
2667void
2668DVBMediaNode::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
2714void
2715DVBMediaNode::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
2740void
2741DVBMediaNode::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
2774void
2775DVBMediaNode::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
2789void
2790DVBMediaNode::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
2807void
2808DVBMediaNode::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
2825void
2826DVBMediaNode::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
2843void
2844DVBMediaNode::AddAudioItems(BDiscreteParameter *param)
2845{
2846	TRACE("DVBMediaNode::AddAudioItems\n");
2847
2848	if (param->CountItems() == 0)
2849		param->AddItem(-1, "default");
2850}
2851
2852
2853status_t
2854DVBMediaNode::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
2887void
2888DVBMediaNode::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
2936status_t
2937DVBMediaNode::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