00001
00010
00011 #include <sys/select.h>
00012 #include <unistd.h>
00013 #include <fcntl.h>
00014
00015
00016 #include <libraw1394/raw1394.h>
00017 #include <libraw1394/csr.h>
00018 #include <libiec61883/iec61883.h>
00019 #include <libavc1394/avc1394.h>
00020 #include <libavc1394/rom1394.h>
00021
00022 #include <netinet/in.h>
00023
00024
00025 #include <algorithm>
00026 #include <map>
00027 using namespace std;
00028
00029
00030 #include <QDateTime>
00031
00032
00033 #include "linuxfirewiredevice.h"
00034 #include "firewirerecorder.h"
00035 #include "mythcorecontext.h"
00036 #include "linuxavcinfo.h"
00037 #include "mythlogging.h"
00038
00039 #define LOC QString("LFireDev(%1): ").arg(guid_to_string(m_guid))
00040
00041 #define kNoDataTimeout 50
00042 #define kResetTimeout 1000
00043
00044 typedef QMap<raw1394handle_t,LinuxFirewireDevice*> handle_to_lfd_t;
00045
00046 class LFDPriv
00047 {
00048 public:
00049 LFDPriv() :
00050 generation(0), reset_timer_on(false),
00051 run_port_handler(false), is_port_handler_running(false),
00052 avstream(NULL), channel(-1),
00053 output_plug(-1), input_plug(-1), bandwidth(0), no_data_cnt(0),
00054 is_p2p_node_open(false), is_bcast_node_open(false),
00055 is_streaming(false), port_handler_thread(NULL)
00056 {
00057 }
00058
00059 ~LFDPriv()
00060 {
00061 avcinfo_list_t::iterator it = devices.begin();
00062 for (; it != devices.end(); ++it)
00063 delete (*it);
00064 devices.clear();
00065
00066 if (port_handler_thread)
00067 {
00068 port_handler_thread->wait();
00069 delete port_handler_thread;
00070 }
00071 }
00072
00073 uint generation;
00074 bool reset_timer_on;
00075 MythTimer reset_timer;
00076
00077 bool run_port_handler;
00078 bool is_port_handler_running;
00079 QWaitCondition port_handler_wait;
00080 QMutex start_stop_port_handler_lock;
00081
00082 iec61883_mpeg2_t avstream;
00083 int channel;
00084 int output_plug;
00085 int input_plug;
00086 int bandwidth;
00087 uint no_data_cnt;
00088
00089 bool is_p2p_node_open;
00090 bool is_bcast_node_open;
00091 bool is_streaming;
00092
00093 QDateTime stop_streaming_timer;
00094 MThread *port_handler_thread;
00095
00096 avcinfo_list_t devices;
00097
00098 static QMutex s_lock;
00099 static handle_to_lfd_t s_handle_info;
00100 };
00101 QMutex LFDPriv::s_lock;
00102 handle_to_lfd_t LFDPriv::s_handle_info;
00103
00104 static void add_handle(raw1394handle_t handle, LinuxFirewireDevice *dev)
00105 {
00106 QMutexLocker slocker(&LFDPriv::s_lock);
00107 LFDPriv::s_handle_info[handle] = dev;
00108 }
00109
00110 static void remove_handle(raw1394handle_t handle)
00111 {
00112 QMutexLocker slocker(&LFDPriv::s_lock);
00113 LFDPriv::s_handle_info.remove(handle);
00114 }
00115
00116 const uint LinuxFirewireDevice::kBroadcastChannel = 63;
00117 const uint LinuxFirewireDevice::kConnectionP2P = 0;
00118 const uint LinuxFirewireDevice::kConnectionBroadcast = 1;
00119 const uint LinuxFirewireDevice::kMaxBufferedPackets = 4 * 1024 * 1024 / 188;
00120
00121
00122 int linux_firewire_device_tspacket_handler(
00123 unsigned char *tspacket, int len, uint dropped, void *callback_data);
00124 void *linux_firewire_device_port_handler_thunk(void *param);
00125 static bool has_data(int fd, uint msec);
00126 static QString speed_to_string(uint speed);
00127 static int linux_firewire_device_bus_reset_handler(
00128 raw1394handle_t handle, uint generation);
00129
00130 LinuxFirewireDevice::LinuxFirewireDevice(
00131 uint64_t guid, uint subunitid,
00132 uint speed, bool use_p2p, uint av_buffer_size_in_bytes) :
00133 FirewireDevice(guid, subunitid, speed),
00134 m_bufsz(av_buffer_size_in_bytes),
00135 m_db_reset_disabled(false),
00136 m_use_p2p(use_p2p), m_priv(new LFDPriv())
00137 {
00138 if (!m_bufsz)
00139 m_bufsz = gCoreContext->GetNumSetting("HDRingbufferSize");
00140
00141 m_db_reset_disabled = gCoreContext->GetNumSetting("DisableFirewireReset", 0);
00142
00143 UpdateDeviceList();
00144 }
00145
00146 LinuxFirewireDevice::~LinuxFirewireDevice()
00147 {
00148 if (IsPortOpen())
00149 {
00150 LOG(VB_GENERAL, LOG_ERR, LOC + "ctor called with open port");
00151 while (IsPortOpen())
00152 ClosePort();
00153 }
00154
00155 if (m_priv)
00156 {
00157 delete m_priv;
00158 m_priv = NULL;
00159 }
00160 }
00161
00162 void LinuxFirewireDevice::SignalReset(uint generation)
00163 {
00164 const QString loc = LOC + QString("SignalReset(%1->%2)")
00165 .arg(m_priv->generation).arg(generation);
00166
00167 LOG(VB_GENERAL, LOG_INFO, loc);
00168
00169 if (GetInfoPtr())
00170 raw1394_update_generation(GetInfoPtr()->fw_handle, generation);
00171
00172 m_priv->generation = generation;
00173
00174 LOG(VB_GENERAL, LOG_INFO, loc + ": Updating device list -- begin");
00175 UpdateDeviceList();
00176 LOG(VB_GENERAL, LOG_INFO, loc + ": Updating device list -- end");
00177
00178 m_priv->reset_timer_on = true;
00179 m_priv->reset_timer.start();
00180 }
00181
00182 void LinuxFirewireDevice::HandleBusReset(void)
00183 {
00184 const QString loc = LOC + "HandleBusReset";
00185
00186 if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
00187 return;
00188
00189 if (m_priv->is_p2p_node_open)
00190 {
00191 LOG(VB_GENERAL, LOG_INFO, loc + ": Reconnecting P2P connection");
00192 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00193 nodeid_t input = raw1394_get_local_id(GetInfoPtr()->fw_handle);
00194
00195 int fwchan = iec61883_cmp_reconnect(
00196 GetInfoPtr()->fw_handle,
00197 output, &m_priv->output_plug,
00198 input, &m_priv->input_plug,
00199 &m_priv->bandwidth, m_priv->channel);
00200
00201 if (fwchan < 0)
00202 {
00203 LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset: Failed to reconnect");
00204 }
00205 else if (fwchan != m_priv->channel)
00206 {
00207 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("FWChan changed %1->%2")
00208 .arg(m_priv->channel).arg(fwchan));
00209 }
00210 m_priv->channel = fwchan;
00211
00212 LOG(VB_GENERAL, LOG_INFO,
00213 loc + QString(": Reconnected fwchan: %1\n\t\t\toutput: 0x%2 "
00214 "input: 0x%3")
00215 .arg(fwchan).arg(output,0,16).arg(input,0,16));
00216 }
00217
00218 if (m_priv->is_bcast_node_open)
00219 {
00220 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00221
00222 LOG(VB_RECORD, LOG_INFO, loc + ": Restarting broadcast connection on " +
00223 QString("node %1, channel %2")
00224 .arg(GetInfoPtr()->GetNode()).arg(m_priv->channel));
00225
00226 int err = iec61883_cmp_create_bcast_output(
00227 GetInfoPtr()->fw_handle,
00228 output, m_priv->output_plug,
00229 m_priv->channel, m_speed);
00230
00231 if (err < 0)
00232 {
00233 LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset : Failed to reconnect");
00234 }
00235 }
00236 }
00237
00238 bool LinuxFirewireDevice::OpenPort(void)
00239 {
00240 LOG(VB_RECORD, LOG_INFO, LOC + "Starting Port Handler Thread");
00241 QMutexLocker locker(&m_priv->start_stop_port_handler_lock);
00242 LOG(VB_RECORD, LOG_INFO, LOC + "Starting Port Handler Thread -- locked");
00243
00244 LOG(VB_RECORD, LOG_INFO, LOC + "OpenPort()");
00245
00246 QMutexLocker mlocker(&m_lock);
00247
00248 LOG(VB_RECORD, LOG_INFO, LOC + "OpenPort() -- got lock");
00249
00250 if (!GetInfoPtr())
00251 return false;
00252
00253 if (GetInfoPtr()->IsPortOpen())
00254 {
00255 m_open_port_cnt++;
00256 return true;
00257 }
00258
00259 if (!GetInfoPtr()->OpenPort())
00260 return false;
00261
00262 add_handle(GetInfoPtr()->fw_handle, this);
00263
00264 m_priv->generation = raw1394_get_generation(GetInfoPtr()->fw_handle);
00265 raw1394_set_bus_reset_handler(
00266 GetInfoPtr()->fw_handle, linux_firewire_device_bus_reset_handler);
00267
00268 GetInfoPtr()->GetSubunitInfo();
00269 LOG(VB_RECORD, LOG_INFO, LOC + GetInfoPtr()->GetSubunitInfoString());
00270
00271 if (!GetInfoPtr()->IsSubunitType(kAVCSubunitTypeTuner) ||
00272 !GetInfoPtr()->IsSubunitType(kAVCSubunitTypePanel))
00273 {
00274 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Not an STB"));
00275
00276 mlocker.unlock();
00277 ClosePort();
00278
00279 return false;
00280 }
00281
00282 m_priv->run_port_handler = true;
00283
00284 LOG(VB_RECORD, LOG_INFO, LOC + "Starting port handler thread");
00285 m_priv->port_handler_thread = new MThread("LinuxController", this);
00286 m_priv->port_handler_thread->start();
00287
00288 while (!m_priv->is_port_handler_running)
00289 m_priv->port_handler_wait.wait(mlocker.mutex(), 100);
00290
00291 LOG(VB_RECORD, LOG_INFO, LOC + "Port handler thread started");
00292
00293 m_open_port_cnt++;
00294
00295 return true;
00296 }
00297
00298 bool LinuxFirewireDevice::ClosePort(void)
00299 {
00300 LOG(VB_RECORD, LOG_INFO, LOC + "Stopping Port Handler Thread");
00301 QMutexLocker locker(&m_priv->start_stop_port_handler_lock);
00302 LOG(VB_RECORD, LOG_INFO, LOC + "Stopping Port Handler Thread -- locked");
00303
00304 QMutexLocker mlocker(&m_lock);
00305
00306 LOG(VB_RECORD, LOG_INFO, LOC + "ClosePort()");
00307
00308 if (m_open_port_cnt < 1)
00309 return false;
00310
00311 m_open_port_cnt--;
00312
00313 if (m_open_port_cnt != 0)
00314 return true;
00315
00316 if (!GetInfoPtr())
00317 return false;
00318
00319 if (GetInfoPtr()->IsPortOpen())
00320 {
00321 if (IsNodeOpen())
00322 CloseNode();
00323
00324 LOG(VB_RECORD, LOG_INFO,
00325 LOC + "Waiting for port handler thread to stop");
00326 m_priv->run_port_handler = false;
00327 m_priv->port_handler_wait.wakeAll();
00328
00329 mlocker.unlock();
00330 m_priv->port_handler_thread->wait();
00331 mlocker.relock();
00332
00333 delete m_priv->port_handler_thread;
00334 m_priv->port_handler_thread = NULL;
00335
00336 LOG(VB_RECORD, LOG_INFO, LOC + "Joined port handler thread");
00337
00338 remove_handle(GetInfoPtr()->fw_handle);
00339
00340 if (!GetInfoPtr()->ClosePort())
00341 return false;
00342 }
00343
00344 return true;
00345 }
00346
00347 void LinuxFirewireDevice::AddListener(TSDataListener *listener)
00348 {
00349 QMutexLocker locker(&m_lock);
00350
00351 FirewireDevice::AddListener(listener);
00352
00353 if (!m_listeners.empty())
00354 {
00355 OpenNode();
00356 OpenAVStream();
00357 StartStreaming();
00358 }
00359 }
00360
00361 void LinuxFirewireDevice::RemoveListener(TSDataListener *listener)
00362 {
00363 QMutexLocker locker(&m_lock);
00364
00365 FirewireDevice::RemoveListener(listener);
00366
00367 if (m_listeners.empty())
00368 {
00369 StopStreaming();
00370 CloseAVStream();
00371 CloseNode();
00372 }
00373 }
00374
00375 bool LinuxFirewireDevice::SendAVCCommand(
00376 const vector<uint8_t> &cmd,
00377 vector<uint8_t> &result,
00378 int retry_cnt)
00379 {
00380 return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
00381 }
00382
00383 bool LinuxFirewireDevice::IsPortOpen(void) const
00384 {
00385 QMutexLocker locker(&m_lock);
00386
00387 if (!GetInfoPtr())
00388 return false;
00389
00390 return GetInfoPtr()->IsPortOpen();
00391 }
00392
00394
00395
00396 bool LinuxFirewireDevice::OpenNode(void)
00397 {
00398 if (m_use_p2p)
00399 return OpenP2PNode();
00400 else
00401 return OpenBroadcastNode();
00402 }
00403
00404 bool LinuxFirewireDevice::CloseNode(void)
00405 {
00406 if (m_priv->is_p2p_node_open)
00407 return CloseP2PNode();
00408
00409 if (m_priv->is_bcast_node_open)
00410 return CloseBroadcastNode();
00411
00412 return true;
00413 }
00414
00415
00416
00417 bool LinuxFirewireDevice::OpenP2PNode(void)
00418 {
00419 if (m_priv->is_bcast_node_open)
00420 return false;
00421
00422 if (m_priv->is_p2p_node_open)
00423 return true;
00424
00425 LOG(VB_RECORD, LOG_INFO, LOC + "Opening P2P connection");
00426
00427 m_priv->bandwidth = +1;
00428 m_priv->output_plug = -1;
00429 m_priv->input_plug = -1;
00430 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00431 nodeid_t input = raw1394_get_local_id(GetInfoPtr()->fw_handle);
00432 m_priv->channel = iec61883_cmp_connect(GetInfoPtr()->fw_handle,
00433 output, &m_priv->output_plug,
00434 input, &m_priv->input_plug,
00435 &m_priv->bandwidth);
00436
00437 if (m_priv->channel < 0)
00438 {
00439 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create P2P connection");
00440
00441 m_priv->bandwidth = 0;
00442
00443 return false;
00444 }
00445
00446 m_priv->is_p2p_node_open = true;
00447
00448 return true;
00449 }
00450
00451 bool LinuxFirewireDevice::CloseP2PNode(void)
00452 {
00453 if (m_priv->is_p2p_node_open && (m_priv->channel >= 0))
00454 {
00455 LOG(VB_RECORD, LOG_INFO, LOC + "Closing P2P connection");
00456
00457 if (m_priv->avstream)
00458 CloseAVStream();
00459
00460 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00461 nodeid_t input = raw1394_get_local_id(GetInfoPtr()->fw_handle);
00462
00463 iec61883_cmp_disconnect(GetInfoPtr()->fw_handle,
00464 output, m_priv->output_plug,
00465 input, m_priv->input_plug,
00466 m_priv->channel, m_priv->bandwidth);
00467
00468 m_priv->channel = -1;
00469 m_priv->output_plug = -1;
00470 m_priv->input_plug = -1;
00471 m_priv->is_p2p_node_open = false;
00472 }
00473
00474 return true;
00475 }
00476
00477 bool LinuxFirewireDevice::OpenBroadcastNode(void)
00478 {
00479 if (m_priv->is_p2p_node_open)
00480 return false;
00481
00482 if (m_priv->is_bcast_node_open)
00483 return true;
00484
00485 if (m_priv->avstream)
00486 CloseAVStream();
00487
00488 m_priv->channel = kBroadcastChannel - GetInfoPtr()->GetNode();
00489 m_priv->output_plug = 0;
00490 m_priv->input_plug = 0;
00491 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00492
00493 LOG(VB_RECORD, LOG_INFO, LOC + "Opening broadcast connection on " +
00494 QString("node %1, channel %2")
00495 .arg(GetInfoPtr()->GetNode()).arg(m_priv->channel));
00496
00497 int err = iec61883_cmp_create_bcast_output(
00498 GetInfoPtr()->fw_handle,
00499 output, m_priv->output_plug,
00500 m_priv->channel, m_speed);
00501
00502 if (err != 0)
00503 {
00504 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Broadcast connection");
00505
00506 m_priv->channel = -1;
00507 m_priv->output_plug = -1;
00508 m_priv->input_plug = -1;
00509
00510 return false;
00511 }
00512
00513 m_priv->is_bcast_node_open = true;
00514
00515 return true;
00516 }
00517
00518 bool LinuxFirewireDevice::CloseBroadcastNode(void)
00519 {
00520 if (m_priv->is_bcast_node_open)
00521 {
00522 LOG(VB_RECORD, LOG_INFO, LOC + "Closing broadcast connection");
00523
00524 m_priv->channel = -1;
00525 m_priv->output_plug = -1;
00526 m_priv->input_plug = -1;
00527 m_priv->is_bcast_node_open = false;
00528 }
00529 return true;
00530 }
00531
00532 bool LinuxFirewireDevice::OpenAVStream(void)
00533 {
00534 LOG(VB_RECORD, LOG_INFO, LOC + "OpenAVStream");
00535
00536 if (!GetInfoPtr() || !GetInfoPtr()->IsPortOpen())
00537 {
00538 LOG(VB_GENERAL, LOG_ERR, LOC +
00539 "Cannot open AVStream without open IEEE 1394 port");
00540
00541 return false;
00542 }
00543
00544 if (!IsNodeOpen() && !OpenNode())
00545 return false;
00546
00547 if (m_priv->avstream)
00548 return true;
00549
00550 LOG(VB_RECORD, LOG_INFO, LOC + "Opening A/V stream object");
00551
00552 m_priv->avstream = iec61883_mpeg2_recv_init(
00553 GetInfoPtr()->fw_handle, linux_firewire_device_tspacket_handler, this);
00554
00555 if (!m_priv->avstream)
00556 {
00557 LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to open AVStream" + ENO);
00558
00559 return false;
00560 }
00561
00562 iec61883_mpeg2_set_synch(m_priv->avstream, 1 );
00563
00564 if (m_bufsz)
00565 SetAVStreamBufferSize(m_bufsz);
00566
00567 return true;
00568 }
00569
00570 bool LinuxFirewireDevice::CloseAVStream(void)
00571 {
00572 if (!m_priv->avstream)
00573 return true;
00574
00575 LOG(VB_RECORD, LOG_INFO, LOC + "Closing A/V stream object");
00576
00577 while (m_listeners.size())
00578 FirewireDevice::RemoveListener(m_listeners[m_listeners.size() - 1]);
00579
00580 if (m_priv->is_streaming)
00581 StopStreaming();
00582
00583 iec61883_mpeg2_close(m_priv->avstream);
00584 m_priv->avstream = NULL;
00585
00586 return true;
00587 }
00588
00589 void LinuxFirewireDevice::run(void)
00590 {
00591 LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- start");
00592 m_lock.lock();
00593 LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- got first lock");
00594 m_priv->is_port_handler_running = true;
00595 m_priv->port_handler_wait.wakeAll();
00596
00597 m_lock.unlock();
00598 usleep(2500);
00599 m_lock.lock();
00600
00601 m_priv->no_data_cnt = 0;
00602 while (m_priv->run_port_handler)
00603 {
00604 LFDPriv::s_lock.lock();
00605 bool reset_timer_on = m_priv->reset_timer_on;
00606 bool handle_reset = reset_timer_on &&
00607 (m_priv->reset_timer.elapsed() > 100);
00608 if (handle_reset)
00609 m_priv->reset_timer_on = false;
00610 LFDPriv::s_lock.unlock();
00611
00612 if (handle_reset)
00613 HandleBusReset();
00614
00615 if (!reset_timer_on && m_priv->is_streaming &&
00616 (m_priv->no_data_cnt > (kResetTimeout / kNoDataTimeout)))
00617 {
00618 m_priv->no_data_cnt = 0;
00619 ResetBus();
00620 }
00621
00622 int fwfd = raw1394_get_fd(GetInfoPtr()->fw_handle);
00623 if (fwfd < 0)
00624 {
00625
00626
00627 m_priv->port_handler_wait.wait(&m_lock, kNoDataTimeout);
00628
00629 m_priv->no_data_cnt += (m_priv->is_streaming) ? 1 : 0;
00630 continue;
00631 }
00632
00633
00634
00635
00636
00637 m_lock.unlock();
00638 bool ready = has_data(fwfd, kNoDataTimeout);
00639 m_lock.lock();
00640
00641 if (!ready && m_priv->is_streaming)
00642 {
00643 m_priv->no_data_cnt++;
00644
00645 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No Input in %1 msec...")
00646 .arg(m_priv->no_data_cnt * kNoDataTimeout));
00647 }
00648
00649
00650 if (ready && has_data(fwfd, 1 ))
00651 {
00652
00653
00654
00655
00656
00657 int ret = raw1394_loop_iterate(GetInfoPtr()->fw_handle);
00658 if (-1 == ret)
00659 {
00660 LOG(VB_GENERAL, LOG_ERR, LOC + "raw1394_loop_iterate" + ENO);
00661 }
00662 }
00663 }
00664
00665 m_priv->is_port_handler_running = false;
00666 m_priv->port_handler_wait.wakeAll();
00667 m_lock.unlock();
00668 LOG(VB_RECORD, LOG_INFO, LOC + "RunPortHandler -- end");
00669 }
00670
00671 bool LinuxFirewireDevice::StartStreaming(void)
00672 {
00673 if (m_priv->is_streaming)
00674 return m_priv->is_streaming;
00675
00676 if (!IsAVStreamOpen() && !OpenAVStream())
00677 return false;
00678
00679 if (m_priv->channel < 0)
00680 {
00681 LOG(VB_GENERAL, LOG_ERR, LOC + "Starting A/V streaming, no channel");
00682 return false;
00683 }
00684
00685 LOG(VB_RECORD, LOG_INFO, LOC + "Starting A/V streaming -- really");
00686
00687 if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0)
00688 {
00689 m_priv->is_streaming = true;
00690 }
00691 else
00692 {
00693 LOG(VB_GENERAL, LOG_ERR, LOC + "Starting A/V streaming " + ENO);
00694 }
00695
00696 LOG(VB_RECORD, LOG_INFO, LOC + "Starting A/V streaming -- done");
00697
00698 return m_priv->is_streaming;
00699 }
00700
00701 bool LinuxFirewireDevice::StopStreaming(void)
00702 {
00703 if (m_priv->is_streaming)
00704 {
00705 LOG(VB_RECORD, LOG_INFO, LOC + "Stopping A/V streaming -- really");
00706
00707 m_priv->is_streaming = false;
00708
00709 iec61883_mpeg2_recv_stop(m_priv->avstream);
00710
00711 raw1394_iso_recv_flush(GetInfoPtr()->fw_handle);
00712 }
00713
00714 LOG(VB_RECORD, LOG_INFO, LOC + "Stopped A/V streaming");
00715
00716 return true;
00717 }
00718
00719 bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes)
00720 {
00721 if (!m_priv->avstream)
00722 return false;
00723
00724
00725 uint buffer_size = max(size_in_bytes, 50 * TSPacket::kSize);
00726 size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets);
00727
00728 iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets);
00729
00730 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Buffered packets %1 (%2 KB)")
00731 .arg(buffered_packets).arg(buffered_packets * 4));
00732
00733 return true;
00734 }
00735
00736 bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed)
00737 {
00738 if (!m_priv->avstream)
00739 return false;
00740
00741 uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream);
00742
00743 if (curspeed == speed)
00744 {
00745 m_speed = speed;
00746 return true;
00747 }
00748
00749 LOG(VB_RECORD, LOG_INFO, LOC + QString("Changing Speed %1 -> %2")
00750 .arg(speed_to_string(curspeed))
00751 .arg(speed_to_string(m_speed)));
00752
00753 iec61883_mpeg2_set_speed(m_priv->avstream, speed);
00754
00755 if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream))
00756 {
00757 m_speed = speed;
00758 return true;
00759 }
00760
00761 LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to set firewire speed.");
00762
00763 return false;
00764 }
00765
00766 bool LinuxFirewireDevice::IsNodeOpen(void) const
00767 {
00768 return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open;
00769 }
00770
00771 bool LinuxFirewireDevice::IsAVStreamOpen(void) const
00772 {
00773 return m_priv->avstream;
00774 }
00775
00776 bool LinuxFirewireDevice::ResetBus(void)
00777 {
00778 LOG(VB_GENERAL, LOG_INFO, LOC + "ResetBus() -- begin");
00779
00780 if (m_db_reset_disabled)
00781 {
00782 LOG(VB_GENERAL, LOG_WARNING, LOC + "Bus Reset disabled" + ENO);
00783 LOG(VB_GENERAL, LOG_INFO, LOC + "ResetBus() -- end");
00784 return true;
00785 }
00786
00787 bool ok = (raw1394_reset_bus_new(GetInfoPtr()->fw_handle,
00788 RAW1394_LONG_RESET) == 0);
00789 if (!ok)
00790 LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset failed" + ENO);
00791
00792 LOG(VB_GENERAL, LOG_INFO, LOC + "ResetBus() -- end");
00793
00794 return ok;
00795 }
00796
00797 void LinuxFirewireDevice::PrintDropped(uint dropped_packets)
00798 {
00799 if (dropped_packets == 1)
00800 {
00801 LOG(VB_RECORD, LOG_ERR, LOC + "Dropped a TS packet");
00802 }
00803 else if (dropped_packets > 1)
00804 {
00805 LOG(VB_RECORD, LOG_ERR, LOC + QString("Dropped %1 TS packets")
00806 .arg(dropped_packets));
00807 }
00808 }
00809
00810 vector<AVCInfo> LinuxFirewireDevice::GetSTBList(void)
00811 {
00812 vector<AVCInfo> list;
00813
00814 {
00815 LinuxFirewireDevice dev(0,0,0,false);
00816 list = dev.GetSTBListPrivate();
00817 }
00818
00819 return list;
00820 }
00821
00822 vector<AVCInfo> LinuxFirewireDevice::GetSTBListPrivate(void)
00823 {
00824 #if 0
00825 LOG(VB_GENERAL, LOG_DEBUG, "GetSTBListPrivate -- begin");
00826 #endif
00827 QMutexLocker locker(&m_lock);
00828 #if 0
00829 LOG(VB_GENERAL, LOG_DEBUG, "GetSTBListPrivate -- got lock");
00830 #endif
00831
00832 vector<AVCInfo> list;
00833
00834 avcinfo_list_t::iterator it = m_priv->devices.begin();
00835 for (; it != m_priv->devices.end(); ++it)
00836 {
00837 if ((*it)->IsSubunitType(kAVCSubunitTypeTuner) &&
00838 (*it)->IsSubunitType(kAVCSubunitTypePanel))
00839 {
00840 list.push_back(*(*it));
00841 }
00842 }
00843
00844 #if 0
00845 LOG(VB_GENERAL, LOG_DEBUG, "GetSTBListPrivate -- end");
00846 #endif
00847 return list;
00848 }
00849
00850 typedef struct
00851 {
00852 raw1394handle_t handle;
00853 int port;
00854 int node;
00855 } dev_item;
00856
00857 bool LinuxFirewireDevice::UpdateDeviceList(void)
00858 {
00859 dev_item item;
00860
00861 item.handle = raw1394_new_handle();
00862 if (!item.handle)
00863 {
00864 LOG(VB_GENERAL, LOG_ERR, QString("LinuxFirewireDevice: ") +
00865 "Couldn't get handle" + ENO);
00866 return false;
00867 }
00868
00869 struct raw1394_portinfo port_info[16];
00870 int numcards = raw1394_get_port_info(item.handle, port_info, 16);
00871 if (numcards < 1)
00872 {
00873 raw1394_destroy_handle(item.handle);
00874 return true;
00875 }
00876
00877 map<uint64_t,bool> guid_online;
00878 for (int port = 0; port < numcards; port++)
00879 {
00880 if (raw1394_set_port(item.handle, port) < 0)
00881 {
00882 LOG(VB_GENERAL, LOG_ERR, QString("LinuxFirewireDevice: "
00883 "Couldn't set port to %1").arg(port));
00884 continue;
00885 }
00886
00887 for (int node = 0; node < raw1394_get_nodecount(item.handle); node++)
00888 {
00889 uint64_t guid;
00890
00891 guid = rom1394_get_guid(item.handle, node);
00892 item.port = port;
00893 item.node = node;
00894 UpdateDeviceListItem(guid, &item);
00895 guid_online[guid] = true;
00896 }
00897
00898 raw1394_destroy_handle(item.handle);
00899
00900 item.handle = raw1394_new_handle();
00901 if (!item.handle)
00902 {
00903 LOG(VB_GENERAL, LOG_ERR, QString("LinuxFirewireDevice: ") +
00904 "Couldn't get handle " +
00905 QString("(after setting port %1").arg(port) + ENO);
00906 item.handle = NULL;
00907 break;
00908 }
00909
00910 numcards = raw1394_get_port_info(item.handle, port_info, 16);
00911 }
00912
00913 if (item.handle)
00914 {
00915 raw1394_destroy_handle(item.handle);
00916 item.handle = NULL;
00917 }
00918
00919 item.port = -1;
00920 item.node = -1;
00921 avcinfo_list_t::iterator it = m_priv->devices.begin();
00922 for (; it != m_priv->devices.end(); ++it)
00923 {
00924 if (!guid_online[it.key()])
00925 UpdateDeviceListItem(it.key(), &item);
00926 }
00927
00928 return true;
00929 }
00930
00931 void LinuxFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
00932 {
00933 avcinfo_list_t::iterator it = m_priv->devices.find(guid);
00934
00935 if (it == m_priv->devices.end())
00936 {
00937 LinuxAVCInfo *ptr = new LinuxAVCInfo();
00938
00939 LOG(VB_RECORD, LOG_INFO, LOC + QString("Adding 0x%1").arg(guid,0,16));
00940
00941 m_priv->devices[guid] = ptr;
00942 it = m_priv->devices.find(guid);
00943 }
00944
00945 if (it != m_priv->devices.end())
00946 {
00947 dev_item &item = *((dev_item*) pitem);
00948 LOG(VB_RECORD, LOG_INFO,
00949 LOC + QString("Updating 0x%1 port: %2 node: %3")
00950 .arg(guid,0,16).arg(item.port).arg(item.node));
00951
00952 (*it)->Update(guid, item.handle, item.port, item.node);
00953 }
00954 }
00955
00956 LinuxAVCInfo *LinuxFirewireDevice::GetInfoPtr(void)
00957 {
00958 if (!m_priv)
00959 return NULL;
00960
00961 avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
00962 return (it == m_priv->devices.end()) ? NULL : *it;
00963 }
00964
00965 const LinuxAVCInfo *LinuxFirewireDevice::GetInfoPtr(void) const
00966 {
00967 if (!m_priv)
00968 return NULL;
00969
00970 avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
00971 return (it == m_priv->devices.end()) ? NULL : *it;
00972 }
00973
00974 int linux_firewire_device_tspacket_handler(
00975 unsigned char *tspacket, int len, uint dropped, void *callback_data)
00976 {
00977 LinuxFirewireDevice *fw =
00978 reinterpret_cast<LinuxFirewireDevice*>(callback_data);
00979
00980 if (!fw)
00981 return 0;
00982
00983 if (dropped)
00984 fw->PrintDropped(dropped);
00985
00986 if (len > 0)
00987 fw->BroadcastToListeners(tspacket, len);
00988
00989 return 1;
00990 }
00991
00992 static bool has_data(int fd, uint msec)
00993 {
00994 fd_set rfds;
00995 FD_ZERO(&rfds);
00996 FD_SET(fd, &rfds);
00997
00998 struct timeval tv;
00999 tv.tv_sec = msec / 1000;
01000 tv.tv_usec = (msec % 1000) * 1000;
01001
01002 int ready = select(fd + 1, &rfds, NULL, NULL, &tv);
01003
01004 if (ready < 0)
01005 LOG(VB_GENERAL, LOG_ERR, "LFireDev: Select Error" + ENO);
01006
01007 if (ready <= 0)
01008 return false;
01009
01010 return true;
01011 }
01012
01013 static QString speed_to_string(uint speed)
01014 {
01015 if (speed > 3)
01016 return QString("Invalid Speed (%1)").arg(speed);
01017
01018 static const uint speeds[] = { 100, 200, 400, 800 };
01019 return QString("%1Mbps").arg(speeds[speed]);
01020 }
01021
01022 static int linux_firewire_device_bus_reset_handler(
01023 raw1394handle_t handle, unsigned int generation)
01024 {
01025 QMutexLocker locker(&LFDPriv::s_lock);
01026
01027 handle_to_lfd_t::iterator it = LFDPriv::s_handle_info.find(handle);
01028
01029 if (it != LFDPriv::s_handle_info.end())
01030 (*it)->SignalReset(generation);
01031
01032 return 0;
01033 }