bool IPTVChannel::Tune(const IPTVTuningData &tuning) { QMutexLocker locker(&m_lock); LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(%1)") .arg(tuning.GetDeviceName())); if (tuning.GetDataURL().scheme().toUpper() == "RTSP") { // TODO get RTP info using RTSP } if (!tuning.IsValid()) { LOG(VB_CHANNEL, LOG_ERR, LOC + QString("Invalid tuning info %1") .arg(tuning.GetDeviceName())); return false; } if (m_last_tuning == tuning) { LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("Already tuned to %1") .arg(tuning.GetDeviceName())); return true; } m_last_tuning = tuning; if (!m_firsttune) // for historical reason, an initial tune is // requested at startup so don't open the stream // handler just yet it will be opened after the // next Tune or SetStreamData) { MPEGStreamData *tmp = m_stream_data; CloseStreamHandler(); if (tmp) SetStreamData(tmp); else OpenStreamHandler(); } m_firsttune = false; return true; }
IPTVStreamHandler::IPTVStreamHandler(const IPTVTuningData &tuning) : StreamHandler(tuning.GetDeviceKey()), m_tuning(tuning), m_write_helper(NULL), m_buffer(NULL), m_use_rtp_streaming(true) { memset(m_sockets, 0, sizeof(m_sockets)); memset(m_read_helpers, 0, sizeof(m_read_helpers)); m_use_rtp_streaming = m_tuning.GetDataURL().scheme().toUpper() == "RTP"; }
IPTVStreamHandler::IPTVStreamHandler(const IPTVTuningData &tuning, int inputid) : StreamHandler(tuning.GetDeviceKey(), inputid) , m_tuning(tuning) , m_write_helper(nullptr) , m_buffer(nullptr) , m_rtsp_rtp_port(0) , m_rtsp_rtcp_port(0) , m_rtsp_ssrc(0) { memset(m_sockets, 0, sizeof(m_sockets)); memset(m_read_helpers, 0, sizeof(m_read_helpers)); m_use_rtp_streaming = m_tuning.IsRTP(); }
void IPTVStreamHandler::run(void) { RunProlog(); LOG(VB_GENERAL, LOG_INFO, LOC + "run()"); SetRunning(true, false, false); // TODO Error handling.. // Setup CetonRTSP *rtsp = NULL; IPTVTuningData tuning = m_tuning; if (m_tuning.GetURL(0).scheme().toLower() == "rtsp") { rtsp = new CetonRTSP(m_tuning.GetURL(0)); // Check RTSP capabilities QStringList options; if (!(rtsp->GetOptions(options) && options.contains("OPTIONS") && options.contains("DESCRIBE") && options.contains("SETUP") && options.contains("PLAY") && options.contains("TEARDOWN"))) { LOG(VB_RECORD, LOG_ERR, LOC + "RTSP interface did not support the necessary options"); delete rtsp; SetRunning(false, false, false); RunEpilog(); return; } if (!rtsp->Describe()) { LOG(VB_RECORD, LOG_ERR, LOC + "RTSP Describe command failed"); delete rtsp; SetRunning(false, false, false); RunEpilog(); return; } tuning = IPTVTuningData( QString("rtp://%1@%2:0") .arg(m_tuning.GetURL(0).host()) .arg(QHostAddress(QHostAddress::Any).toString()), 0, IPTVTuningData::kNone, QString("rtp://%1@%2:0") .arg(m_tuning.GetURL(0).host()) .arg(QHostAddress(QHostAddress::Any).toString()), 0, "", 0); } for (uint i = 0; i < IPTV_SOCKET_COUNT; i++) { QUrl url = tuning.GetURL(i); if (url.port() < 0) continue; m_sockets[i] = new QUdpSocket(); m_read_helpers[i] = new IPTVStreamHandlerReadHelper( this, m_sockets[i], i); // we need to open the descriptor ourselves so we // can set some socket options int fd = socket(AF_INET, SOCK_DGRAM, 0); // create IPv4 socket if (fd < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to create socket " + ENO); continue; } int buf_size = 2 * 1024 * max(tuning.GetBitrate(i)/1000, 500U); if (!tuning.GetBitrate(i)) buf_size = 2 * 1024 * 1024; int ok = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_size, sizeof(buf_size)); if (ok) { LOG(VB_GENERAL, LOG_INFO, LOC + QString("Increasing buffer size to %1 failed") .arg(buf_size) + ENO); } /* int broadcast = 1; ok = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); if (ok) { LOG(VB_GENERAL, LOG_INFO, LOC + QString("Enabling broadcast failed") + ENO); } */ m_sockets[i]->setSocketDescriptor( fd, QAbstractSocket::UnconnectedState, QIODevice::ReadOnly); m_sockets[i]->bind(QHostAddress::Any, url.port()); QHostAddress dest_addr(tuning.GetURL(i).host()); if (dest_addr != QHostAddress::Any) { //m_sockets[i]->joinMulticastGroup(dest_addr); // needs Qt 4.8 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Joining %1") .arg(dest_addr.toString())); struct ip_mreq imr; memset(&imr, 0, sizeof(struct ip_mreq)); imr.imr_multiaddr.s_addr = inet_addr( dest_addr.toString().toLatin1().constData()); imr.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(imr)) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_ADD_MEMBERSHIP " + ENO); } } if (!url.userInfo().isEmpty()) m_sender[i] = QHostAddress(url.userInfo()); } if (m_use_rtp_streaming) m_buffer = new RTPPacketBuffer(tuning.GetBitrate(0)); else m_buffer = new UDPPacketBuffer(tuning.GetBitrate(0)); m_write_helper = new IPTVStreamHandlerWriteHelper(this); m_write_helper->Start(); bool error = false; if (rtsp) { // Start Streaming if (!rtsp->Setup(m_sockets[0]->localPort(), m_sockets[1]->localPort()) || !rtsp->Play()) { LOG(VB_RECORD, LOG_ERR, LOC + "Starting recording (RTP initialization failed). Aborting."); error = true; } } if (!error) { // Enter event loop exec(); } // Clean up for (uint i = 0; i < IPTV_SOCKET_COUNT; i++) { if (m_sockets[i]) { delete m_sockets[i]; m_sockets[i] = NULL; delete m_read_helpers[i]; m_read_helpers[i] = NULL; } } delete m_buffer; m_buffer = NULL; delete m_write_helper; m_write_helper = NULL; if (rtsp) { rtsp->Teardown(); delete rtsp; } SetRunning(false, false, false); RunEpilog(); }
void IPTVStreamHandler::run(void) { RunProlog(); LOG(VB_GENERAL, LOG_INFO, LOC + "run()"); SetRunning(true, false, false); // TODO Error handling.. // Setup CetonRTSP *rtsp = nullptr; IPTVTuningData tuning = m_tuning; if(m_tuning.IsRTSP()) { rtsp = new CetonRTSP(m_tuning.GetURL(0)); // Check RTSP capabilities QStringList options; if (!(rtsp->GetOptions(options) && options.contains("DESCRIBE") && options.contains("SETUP") && options.contains("PLAY") && options.contains("TEARDOWN"))) { LOG(VB_RECORD, LOG_ERR, LOC + "RTSP interface did not support the necessary options"); delete rtsp; SetRunning(false, false, false); RunEpilog(); return; } if (!rtsp->Describe()) { LOG(VB_RECORD, LOG_ERR, LOC + "RTSP Describe command failed"); delete rtsp; SetRunning(false, false, false); RunEpilog(); return; } m_use_rtp_streaming = true; QUrl urltuned = m_tuning.GetURL(0); urltuned.setScheme("rtp"); urltuned.setPort(0); tuning = IPTVTuningData(urltuned.toString(), 0, IPTVTuningData::kNone, urltuned.toString(), 0, "", 0); } bool error = false; int start_port = 0; for (uint i = 0; i < IPTV_SOCKET_COUNT; i++) { QUrl url = tuning.GetURL(i); if (url.port() < 0) continue; LOG(VB_RECORD, LOG_DEBUG, LOC + QString("setting up url[%1]:%2").arg(i).arg(url.toString())); // always ensure we use consecutive port numbers int port = start_port ? start_port + 1 : url.port(); QString host = url.host(); QHostAddress dest_addr(host); if (!host.isEmpty() && dest_addr.isNull()) { // address is a hostname, attempts to resolve it QHostInfo info = QHostInfo::fromName(host); QList<QHostAddress> list = info.addresses(); if (list.isEmpty()) { LOG(VB_RECORD, LOG_ERR, LOC + QString("Can't resolve hostname:'%1'").arg(host)); } else { for (int j=0; j < list.size(); j++) { dest_addr = list[j]; if (list[j].protocol() == QAbstractSocket::IPv6Protocol) { // We prefer first IPv4 break; } } LOG(VB_RECORD, LOG_DEBUG, LOC + QString("resolved %1 as %2").arg(host).arg(dest_addr.toString())); } } bool ipv6 = dest_addr.protocol() == QAbstractSocket::IPv6Protocol; bool is_multicast = ipv6 ? dest_addr.isInSubnet(QHostAddress::parseSubnet("ff00::/8")) : (dest_addr.toIPv4Address() & 0xf0000000) == 0xe0000000; m_sockets[i] = new QUdpSocket(); if (!is_multicast) { // this allow to filter incoming traffic, and make sure it's from // the requested server m_sender[i] = dest_addr; } m_read_helpers[i] = new IPTVStreamHandlerReadHelper( this, m_sockets[i], i); // we need to open the descriptor ourselves so we // can set some socket options int fd = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); // create IPv4 socket if (fd < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to create socket " + ENO); continue; } int buf_size = 2 * 1024 * max(tuning.GetBitrate(i)/1000, 500U); if (!tuning.GetBitrate(i)) buf_size = 2 * 1024 * 1024; int err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_size, sizeof(buf_size)); if (err) { LOG(VB_GENERAL, LOG_INFO, LOC + QString("Increasing buffer size to %1 failed") .arg(buf_size) + ENO); } m_sockets[i]->setSocketDescriptor( fd, QAbstractSocket::UnconnectedState, QIODevice::ReadOnly); // we bind to destination address if it's a multicast address, or // the local ones otherwise if (!m_sockets[i]->bind(is_multicast ? dest_addr : (ipv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any), port)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Binding to port failed."); error = true; } else { start_port = m_sockets[i]->localPort(); } if (is_multicast) { m_sockets[i]->joinMulticastGroup(dest_addr); LOG(VB_GENERAL, LOG_INFO, LOC + QString("Joining %1") .arg(dest_addr.toString())); } if (!is_multicast && rtsp && i == 1) { m_rtcp_dest = dest_addr; } } if (!error) { if (m_tuning.IsRTP() || m_tuning.IsRTSP()) m_buffer = new RTPPacketBuffer(tuning.GetBitrate(0)); else m_buffer = new UDPPacketBuffer(tuning.GetBitrate(0)); m_write_helper = new IPTVStreamHandlerWriteHelper(this); m_write_helper->Start(); } if (!error && rtsp) { // Start Streaming if (!rtsp->Setup(m_sockets[0]->localPort(), m_sockets[1]->localPort(), m_rtsp_rtp_port, m_rtsp_rtcp_port, m_rtsp_ssrc) || !rtsp->Play()) { LOG(VB_RECORD, LOG_ERR, LOC + "Starting recording (RTP initialization failed). Aborting."); error = true; } if (m_rtsp_rtcp_port > 0) { m_write_helper->SendRTCPReport(); m_write_helper->StartRTCPRR(); } } if (!error) { // Enter event loop exec(); } // Clean up for (uint i = 0; i < IPTV_SOCKET_COUNT; i++) { if (m_sockets[i]) { delete m_sockets[i]; m_sockets[i] = nullptr; delete m_read_helpers[i]; m_read_helpers[i] = nullptr; } } delete m_buffer; m_buffer = nullptr; delete m_write_helper; m_write_helper = nullptr; if (rtsp) { rtsp->Teardown(); delete rtsp; } SetRunning(false, false, false); RunEpilog(); }
void IPTVStreamHandler::run(void) { RunProlog(); LOG(VB_GENERAL, LOG_INFO, LOC + "run()"); SetRunning(true, false, false); // TODO Error handling.. // Setup CetonRTSP *rtsp = NULL; IPTVTuningData tuning = m_tuning; if (m_tuning.GetURL(0).scheme().toLower() == "rtsp") { rtsp = new CetonRTSP(m_tuning.GetURL(0)); // Check RTSP capabilities QStringList options; if (!(rtsp->GetOptions(options) && options.contains("OPTIONS") && options.contains("DESCRIBE") && options.contains("SETUP") && options.contains("PLAY") && options.contains("TEARDOWN"))) { LOG(VB_RECORD, LOG_ERR, LOC + "RTSP interface did not support the necessary options"); delete rtsp; SetRunning(false, false, false); RunEpilog(); return; } if (!rtsp->Describe()) { LOG(VB_RECORD, LOG_ERR, LOC + "RTSP Describe command failed"); delete rtsp; SetRunning(false, false, false); RunEpilog(); return; } tuning = IPTVTuningData( QString("rtp://%1@%2:0") .arg(m_tuning.GetURL(0).host()) .arg(QHostAddress(QHostAddress::Any).toString()), 0, IPTVTuningData::kNone, QString("rtp://%1@%2:0") .arg(m_tuning.GetURL(0).host()) .arg(QHostAddress(QHostAddress::Any).toString()), 0, "", 0); } for (uint i = 0; i < IPTV_SOCKET_COUNT; i++) { QUrl url = tuning.GetURL(i); if (url.port() < 0) continue; m_sockets[i] = new QTcpSocket(); m_sockets[i]->setSocketOption(QAbstractSocket::LowDelayOption, 1); m_read_helpers[i] = new IPTVStreamHandlerReadHelper( this, m_sockets[i], i); if (!url.userInfo().isEmpty()) m_sender[i] = QHostAddress(url.userInfo()); m_sockets[i]->connectToHost(url.host().toAscii(), 3000); if (m_sockets[i]->waitForConnected(1000)) { m_sockets[i]->write("GET " + url.path().toAscii() + " HTTP/1.0\r\n\r\n\r\n\r\n"); m_sockets[i]->waitForBytesWritten(500); } else { qDebug("not Connected!"); m_sockets[i]->connectToHost(url.host().toAscii(), 3000); m_sockets[i]->write("GET " + url.path().toAscii() + " HTTP/1.0\r\n\r\n\r\n\r\n"); m_sockets[i]->waitForBytesWritten(500); } } //if (m_use_rtp_streaming) // m_buffer = new RTPPacketBuffer(tuning.GetBitrate(0)); //else m_buffer = new UDPPacketBuffer(tuning.GetBitrate(0)); m_write_helper = new IPTVStreamHandlerWriteHelper(this); m_write_helper->Start(); bool error = false; /*if (rtsp) { // Start Streaming if (!rtsp->Setup(m_sockets[0]->localPort(), m_sockets[1]->localPort()) || !rtsp->Play()) { LOG(VB_RECORD, LOG_ERR, LOC + "Starting recording (RTP initialization failed). Aborting."); error = true; } } */ if (!error) { // Enter event loop exec(); } // Clean up for (uint i = 0; i < IPTV_SOCKET_COUNT; i++) { if (m_sockets[i]) { delete m_sockets[i]; m_sockets[i] = NULL; delete m_read_helpers[i]; m_read_helpers[i] = NULL; } } delete m_buffer; m_buffer = NULL; delete m_write_helper; m_write_helper = NULL; if (rtsp) { rtsp->Teardown(); delete rtsp; } SetRunning(false, false, false); RunEpilog(); }