2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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.
28 #include <ParameterWeb.h>
29 #include <TimeSource.h>
31 #include "Controller.h"
32 #include "DeviceRoster.h"
33 #include "VideoView.h"
34 #include "VideoNode.h"
36 extern bool gOverlayDisabled
;
38 status_t
MediaRoster_Disconnect(const media_output
&output
, const media_input
&input
);
43 media_node audio_mixer_node
;
44 media_node video_window_node
;
47 media_input audio_input
;
48 media_output audio_output
;
49 media_input video_input
;
50 media_output video_output
;
52 BMediaRoster
*gMediaRoster
;
55 HandleError(const char *text
, status_t err
)
58 printf("%s. error 0x%08x (%s)\n",text
, (int)err
, strerror(err
));
65 Controller::Controller()
66 : fCurrentInterface(-1)
76 gMediaRoster
= BMediaRoster::Roster();
80 Controller::~Controller()
87 Controller::SetVideoView(VideoView
*view
)
94 Controller::SetVideoNode(VideoNode
*node
)
101 Controller::DisconnectInterface()
104 fCurrentInterface
= -1;
105 fCurrentChannel
= -1;
113 Controller::ConnectInterface(int i
)
116 printf("Controller::ConnectInterface: wrong index\n");
119 if (fCurrentInterface
!= -1) {
120 printf("Controller::ConnectInterface: already connected\n");
127 err
= gDeviceRoster
->MediaRoster()->GetParameterWebFor(gDeviceRoster
->DeviceNode(i
), &web
);
129 printf("Controller::ConnectInterface: can't get parameter web\n");
135 fCurrentInterface
= i
;
137 // XXX we may need to monitor for parameter web changes
138 // and reassing fWeb and fChannelParam on demand.
140 // find the channel control and assign it to fChannelParam
141 fChannelParam
= NULL
;
142 int count
= fWeb
->CountParameters();
143 for (int i
= 0; i
< count
; i
++) {
144 BParameter
*parameter
= fWeb
->ParameterAt(i
);
146 printf("parameter %d\n", i
);
147 printf(" name '%s'\n", parameter
->Name());
148 printf(" kind '%s'\n", parameter
->Kind());
149 printf(" unit '%s'\n", parameter
->Unit());
150 printf(" flags 0x%08" B_PRIx32
"\n", parameter
->Flags());
152 // XXX TODO: matching on Name is weak
153 if (strcmp(parameter
->Name(), "Channel") == 0 || strcmp(parameter
->Kind(), B_TUNER_CHANNEL
) == 0) {
154 fChannelParam
= dynamic_cast<BDiscreteParameter
*>(parameter
);
159 if (!fChannelParam
) {
160 printf("Controller::ConnectInterface: can't find channel parameter control\n");
161 fCurrentChannel
= -1;
163 if (fChannelParam
->CountItems() == 0) {
164 fCurrentChannel
= -1;
165 printf("Controller::ConnectInterface: channel control has 0 items\n");
171 size
= sizeof(index
);
172 err
= fChannelParam
->GetValue(&index
, &size
, &when
);
173 if (err
== B_OK
&& size
== sizeof(index
)) {
174 fCurrentChannel
= index
;
175 printf("Controller::ConnectInterface: selected channel is %d\n", fCurrentChannel
);
177 fCurrentChannel
= -1;
178 printf("Controller::ConnectInterface: can't get channel control value\n");
190 Controller::IsInterfaceAvailable(int i
)
192 return gDeviceRoster
->IsRawAudioOutputFree(i
) && gDeviceRoster
->IsRawVideoOutputFree(i
);
197 Controller::CurrentInterface()
199 return fCurrentInterface
;
204 Controller::CurrentChannel()
206 return fCurrentChannel
;
211 Controller::SelectChannel(int i
)
219 err
= fChannelParam
->SetValue(&index
, sizeof(index
), 0);
221 printf("Controller::SelectChannel %d failed\n", i
);
231 Controller::ChannelCount()
233 if (fCurrentInterface
== -1)
239 return fChannelParam
->CountItems();
244 Controller::ChannelName(int i
)
246 if (fCurrentInterface
== -1)
252 return fChannelParam
->ItemNameAt(i
);
257 Controller::VolumeUp()
263 Controller::VolumeDown()
269 Controller::ConnectNodes()
273 // dvb_node = gDeviceRoster->DeviceNode(fCurrentInterface);
275 err
= gMediaRoster
->GetNodeFor(gDeviceRoster
->DeviceNode(fCurrentInterface
).node
, &dvb_node
);
276 HandleError("GetNodeFor failed", err
);
278 video_window_node
= fVideoNode
->Node();
280 err
= gMediaRoster
->GetAudioMixer(&audio_mixer_node
);
281 HandleError("GetAudioMixer failed", err
);
290 err
= gMediaRoster
->GetFreeOutputsFor(dvb_node
, &output
, 1, &count
, B_MEDIA_RAW_AUDIO
);
291 HandleError("Can't find free audio output", err
);
293 HandleError("No free audio output", -1);
295 err
= gMediaRoster
->GetFreeInputsFor(audio_mixer_node
, &input
, 1, &count
, B_MEDIA_RAW_AUDIO
);
296 HandleError("Can't find free audio input", err
);
298 HandleError("No free audio input", -1);
300 memset(&fmt
, 0, sizeof(fmt
));
301 err
= gMediaRoster
->Connect(output
.source
, input
.destination
, &fmt
, &audio_output
, &audio_input
);
302 HandleError("Can't connect audio", err
);
306 err
= gMediaRoster
->GetFreeOutputsFor(dvb_node
, &output
, 1, &count
, B_MEDIA_RAW_VIDEO
);
307 HandleError("Can't find free video output", err
);
309 HandleError("No free video output", -1);
311 err
= gMediaRoster
->GetFreeInputsFor(video_window_node
, &input
, 1, &count
, B_MEDIA_RAW_VIDEO
);
312 HandleError("Can't find free video input", err
);
314 HandleError("No free video input", -1);
316 color_space cspaces_overlay
[] = { B_YCbCr422
, B_RGB32
, B_NO_COLOR_SPACE
};
317 color_space cspaces_bitmap
[] = { B_RGB32
, B_NO_COLOR_SPACE
};
319 if (gOverlayDisabled
) {
322 fVideoNode
->SetOverlayEnabled(true);
323 for (int i
= 0; cspaces_overlay
[i
] != B_NO_COLOR_SPACE
; i
++) {
324 printf("trying connect with colorspace 0x%08x\n", cspaces_overlay
[i
]);
325 memset(&fmt
, 0, sizeof(fmt
));
326 fmt
.type
= B_MEDIA_RAW_VIDEO
;
327 fmt
.u
.raw_video
.display
.format
= cspaces_overlay
[i
];
328 err
= gMediaRoster
->Connect(output
.source
, input
.destination
, &fmt
, &video_output
, &video_input
);
334 fVideoNode
->SetOverlayEnabled(false);
335 for (int i
= 0; cspaces_bitmap
[i
] != B_NO_COLOR_SPACE
; i
++) {
336 printf("trying connect with colorspace 0x%08x\n", cspaces_bitmap
[i
]);
337 memset(&fmt
, 0, sizeof(fmt
));
338 fmt
.type
= B_MEDIA_RAW_VIDEO
;
339 fmt
.u
.raw_video
.display
.format
= cspaces_bitmap
[i
];
340 err
= gMediaRoster
->Connect(output
.source
, input
.destination
, &fmt
, &video_output
, &video_input
);
345 HandleError("Can't connect video", err
);
349 err
= gMediaRoster
->GetTimeSource(&time_node
);
350 HandleError("Can't get time source", err
);
352 BTimeSource
*ts
= gMediaRoster
->MakeTimeSourceFor(time_node
);
354 err
= gMediaRoster
->SetTimeSourceFor(dvb_node
.node
, time_node
.node
);
355 HandleError("Can't set dvb time source", err
);
357 err
= gMediaRoster
->SetTimeSourceFor(audio_mixer_node
.node
, time_node
.node
);
358 HandleError("Can't set audio mixer time source", err
);
360 err
= gMediaRoster
->SetTimeSourceFor(video_window_node
.node
, time_node
.node
);
361 HandleError("Can't set video window time source", err
);
363 // Add a delay of (2 video frames) to the buffers send by the DVB node,
364 // because as a capture device in B_RECORDING run mode it's supposed to
365 // deliver buffers that were captured in the past (and does so).
366 // It is important that the audio buffer size used by the connection with
367 // the DVB node is smaller than this, optimum is the same length as one
368 // video frame (40 ms). However, this is not yet guaranteed.
369 err
= gMediaRoster
->SetProducerRunModeDelay(dvb_node
, 80000);
370 HandleError("Can't set DVB producer delay", err
);
372 bigtime_t start_time
= ts
->Now() + 50000;
378 err
= gMediaRoster
->StartNode(dvb_node
, start_time
);
379 HandleError("Can't start dvb node", err
);
381 err
= gMediaRoster
->StartNode(audio_mixer_node
, start_time
);
382 HandleError("Can't start audio mixer node", err
);
384 err
= gMediaRoster
->StartNode(video_window_node
, start_time
);
385 HandleError("Can't start video window node", err
);
387 printf("running...\n");
396 Controller::DisconnectNodes()
398 printf("stopping...\n");
407 err
= gMediaRoster
->StopNode(dvb_node
, 0, true);
408 HandleError("Can't stop dvb node", err
);
410 err
= gMediaRoster
->StopNode(audio_mixer_node
, 0, true);
411 HandleError("Can't stop audio mixer node", err
);
413 err
= gMediaRoster
->StopNode(video_window_node
, 0, true);
414 HandleError("Can't stop video window node", err
);
418 err
= MediaRoster_Disconnect(video_output
, video_input
);
419 HandleError("Can't disconnect video", err
);
421 err
= MediaRoster_Disconnect(audio_output
, audio_input
);
422 HandleError("Can't disconnect audio", err
);
424 // disable overlay, or erase image
426 fVideoView
->RemoveVideoDisplay();
428 // release other nodes
430 err
= gMediaRoster
->ReleaseNode(audio_mixer_node
);
431 HandleError("Can't release audio mixer node", err
);
433 // err = gMediaRoster->ReleaseNode(video_window_node);
434 // HandleError("Can't release video window node", err);
436 // err = gMediaRoster->ReleaseNode(time_node);
437 // HandleError("Can't release time source node", err);
441 err
= gMediaRoster
->ReleaseNode(dvb_node
);
442 HandleError("Can't release DVB node", err
);
451 MediaRoster_Disconnect(const media_output
&output
, const media_input
&input
)
453 if (output
.node
.node
<= 0) {
454 printf("MediaRoster_Disconnect: output.node.node %d invalid\n",
455 (int)output
.node
.node
);
456 return B_MEDIA_BAD_NODE
;
458 if (input
.node
.node
<= 0) {
459 printf("MediaRoster_Disconnect: input.node.node %d invalid\n",
460 (int)input
.node
.node
);
461 return B_MEDIA_BAD_NODE
;
463 if (!(output
.node
.kind
& B_BUFFER_PRODUCER
)) {
464 printf("MediaRoster_Disconnect: output.node.kind 0x%x is no B_BUFFER_PRODUCER\n",
465 (int)output
.node
.kind
);
466 return B_MEDIA_BAD_NODE
;
468 if (!(input
.node
.kind
& B_BUFFER_CONSUMER
)) {
469 printf("MediaRoster_Disconnect: input.node.kind 0x%x is no B_BUFFER_PRODUCER\n",
470 (int)input
.node
.kind
);
471 return B_MEDIA_BAD_NODE
;
473 if (input
.source
.port
!= output
.source
.port
) {
474 printf("MediaRoster_Disconnect: input.source.port %d doesn't match output.source.port %d\n",
475 (int)input
.source
.port
, (int)output
.source
.port
);
476 return B_MEDIA_BAD_NODE
;
478 if (input
.source
.id
!= output
.source
.id
) {
479 printf("MediaRoster_Disconnect: input.source.id %d doesn't match output.source.id %d\n",
480 (int)input
.source
.id
, (int)output
.source
.id
);
481 return B_MEDIA_BAD_NODE
;
483 if (input
.destination
.port
!= output
.destination
.port
) {
484 printf("MediaRoster_Disconnect: input.destination.port %d doesn't match output.destination.port %d\n",
485 (int)input
.destination
.port
, (int)output
.destination
.port
);
486 return B_MEDIA_BAD_NODE
;
488 if (input
.destination
.id
!= output
.destination
.id
) {
489 printf("MediaRoster_Disconnect: input.destination.id %d doesn't match output.destination.id %d\n",
490 (int)input
.destination
.id
, (int)output
.destination
.id
);
491 return B_MEDIA_BAD_NODE
;
493 return BMediaRoster::Roster()->Disconnect(output
.node
.node
, output
.source
, input
.node
.node
, input
.destination
);