bool MsgChannel::getPacketSync(MsgPacket& out) { std::string header; if ( not getLineSync(header, size_t(MsgPacket::limit_type::MAX_HEADER_SIZE)) ) { PWLOGLIB("failed to get line sync"); return false; } MsgPacket tmp; if ( not tmp.setHeader(header.c_str(), header.size()) ) { PWLOGLIB("failed to set header"); return false; } if ( tmp.getBodySize() ) { blob_type& body(tmp.m_body); if ( not getDataSync(const_cast<char*>(body.buf), body.size) ) { PWLOGLIB("failed to sync body"); return false; } } out.swap(tmp); return true; }
void cLiveStreamer::sendStreamPacket(sStreamPacket *pkt) { bool bReady = IsReady(); if(!bReady || pkt == NULL || pkt->size == 0) return; // Send stream information as the first packet on startup if (IsStarting() && bReady) { // wait for first I-Frame (if enabled) if(m_waitforiframe && pkt->frametype != cStreamInfo::ftIFRAME) { return; } INFOLOG("streaming of channel started"); m_last_tick.Set(0); m_requestStreamChange = true; m_startup = false; } // send stream change on demand if(m_requestStreamChange) sendStreamChange(); // if a audio or video packet was sent, the signal is restored if(m_SignalLost && (pkt->content == cStreamInfo::scVIDEO || pkt->content == cStreamInfo::scAUDIO)) { INFOLOG("signal restored"); sendStatus(XVDR_STREAM_STATUS_SIGNALRESTORED); m_SignalLost = false; m_requestStreamChange = true; m_last_tick.Set(0); return; } if(m_SignalLost) return; // initialise stream packet MsgPacket* packet = new MsgPacket(XVDR_STREAM_MUXPKT, XVDR_CHANNEL_STREAM); packet->disablePayloadCheckSum(); // write stream data packet->put_U16(pkt->pid); packet->put_S64(pkt->pts); packet->put_S64(pkt->dts); if(m_protocolVersion >= 5) { packet->put_U32(pkt->duration); } // write frame type into unused header field clientid packet->setClientID((uint16_t)pkt->frametype); // write payload into stream packet packet->put_U32(pkt->size); packet->put_Blob(pkt->data, pkt->size); m_Queue->Add(packet); m_last_tick.Set(0); }
bool cLiveQueue::Pause(bool on) { cMutexLock lock(&m_lock); // deactivate timeshift if(!on) { m_pause = false; m_cond.Signal(); return true; } if(m_pause) return false; // create offline storage if(m_readfd == -1) { m_storage = cString::sprintf("%s/xvdr-ringbuffer-%05i.data", (const char*)TimeShiftDir, m_socket); DEBUGLOG("FILE: %s", (const char*)m_storage); m_readfd = open(m_storage, O_CREAT | O_RDONLY, 0644); m_writefd = open(m_storage, O_CREAT | O_WRONLY, 0644); lseek(m_readfd, 0, SEEK_SET); lseek(m_writefd, 0, SEEK_SET); if(m_readfd == -1) { ERRORLOG("Failed to create timeshift ringbuffer !"); } } m_pause = true; // push all packets from the queue to the offline storage DEBUGLOG("Writing %i packets into timeshift buffer", size()); while(!empty()) { MsgPacket* p = front(); p->write(m_writefd, 1000); delete p; pop(); } return true; }
Demux::SwitchStatus Demux::SwitchChannel(uint32_t channeluid) { m_client->Log(DEBUG, "changing to channel %d (priority %i)", channeluid, m_priority); { MutexLock lock(&m_lock); m_queuelocked = true; } CleanupPacketQueue(); m_cond.Signal(); MsgPacket vrp(XVDR_CHANNELSTREAM_OPEN); vrp.put_U32(channeluid); vrp.put_S32(m_priority); vrp.put_U8(m_iframestart); MsgPacket* vresp = ReadResult(&vrp); { MutexLock lock(&m_lock); m_queuelocked = false; m_paused = false; m_timeshiftmode = false; m_streams.clear(); } SwitchStatus status = SC_OK; if(vresp != NULL) status = (SwitchStatus)vresp->get_U32(); delete vresp; if(status == SC_OK) { m_channeluid = channeluid; m_client->Log(INFO, "sucessfully switched channel"); } else m_client->Log(FAILURE, "%s - failed to set channel (status: %i)", __FUNCTION__, status); m_cond.Signal(); return status; }
void cLiveQueue::Action() { INFOLOG("LiveQueue started"); // wait for first packet m_cond.Wait(0); while(Running()) { MsgPacket* p = NULL; m_lock.Lock(); // just wait if we are paused if(m_pause) { m_lock.Unlock(); m_cond.Wait(0); m_lock.Lock(); } // check packet queue if(size() > 0) { p = front(); pop(); } m_lock.Unlock(); // no packets to send if(p == NULL) { m_cond.Wait(3000); continue; } // send packet else { p->write(m_socket, 500); delete p; } } INFOLOG("LiveQueue stopped"); }
void MsgHandlerJSON::Run() { std::string msg; syslog(LOG_INFO, "JSON message handler started"); m_closed = false; while(IsRunning()) { // exit if connection was closed if(m_closed) { break; } // wait for string if(!ReceiveString(msg)) { continue; } std::cout << msg << std::endl; // check for http request if(msg.substr(0, 8) == "OPTIONS " && msg.size() > 8) { msg = msg.substr(8); } else if(msg.substr(0, 4) != "GET ") { continue; } std::string::size_type p = msg.rfind("HTTP/"); if(p == std::string::npos) { continue; } msg = msg.substr(0, p); std::cout << "URI: " << msg << std::endl; // extract JSON query string p = msg.find("?"); std::string url; std::string query; if(p > 0) { url = msg.substr(0, p); } if(p < msg.size() - 1) { query = URLDecode(msg.substr(p + 1)); } std::cout << "URL: " << url << std::endl; std::cout << "QUERY: " << query << std::endl; // get message id while((url[0] > '9' || url[0] < '0') && url.size() > 1) { url = url.substr(1); } uint32_t msgid = atoi(url.c_str()); MsgPacket* request = MsgPacketFromJSON(query, msgid); if(m_msgtype != 0) { request->setType(m_msgtype); } std::cout << "MSGID: " << request->getMsgID() << std::endl; std::cout << "MSGTYPE: " << request->getType() << std::endl; request->print(); MsgPacket* response = new MsgPacket(request->getMsgID(), request->getType(), request->getUID()); std::string jsonformat; std::string result; request->rewind(); if(OnMessage(request, response)) { if(OnCustomJSONResponse(response, result)) { SendHTTPResponse(result); } else if(OnResponseFormat(response, jsonformat)) { result = MsgPacketToJSON(response, jsonformat); SendHTTPResponse(result); } } delete response; delete request; } }
void cLiveStreamer::RequestSignalInfo() { cMutexLock lock(&m_DeviceMutex); if(!Running() || m_Device == NULL) { return; } // do not send (and pollute the client with) signal information // if we are paused if(IsPaused()) return; MsgPacket* resp = new MsgPacket(XVDR_STREAM_SIGNALINFO, XVDR_CHANNEL_STREAM); int DeviceNumber = m_Device->DeviceNumber() + 1; int Strength = 0; int Quality = 0; if(!TimeShiftMode()) { Strength = m_Device->SignalStrength(); Quality = m_Device->SignalQuality(); } resp->put_String(*cString::sprintf("%s #%d - %s", #if VDRVERSNUM < 10728 #warning "VDR versions < 1.7.28 do not support all features" "Unknown", DeviceNumber, "Unknown")); #else (const char*)m_Device->DeviceType(), DeviceNumber, (const char*)m_Device->DeviceName())); #endif // Quality: // 4 - NO LOCK // 3 - NO SYNC // 2 - NO VITERBI // 1 - NO CARRIER // 0 - NO SIGNAL if(TimeShiftMode()) { resp->put_String("TIMESHIFT"); } else if(Quality == -1) { resp->put_String("UNKNOWN (Incompatible device)"); Quality = 0; } else resp->put_String(*cString::sprintf("%s:%s:%s:%s:%s", (Quality > 4) ? "LOCKED" : "-", (Quality > 0) ? "SIGNAL" : "-", (Quality > 1) ? "CARRIER" : "-", (Quality > 2) ? "VITERBI" : "-", (Quality > 3) ? "SYNC" : "-")); resp->put_U32((Strength << 16 ) / 100); resp->put_U32((Quality << 16 ) / 100); resp->put_U32(0); resp->put_U32(0); // get provider & service information const cChannel* channel = FindChannelByUID(m_uid); if(channel != NULL) { // put in provider name resp->put_String(channel->Provider()); // what the heck should be the service name ? // using PortalName for now resp->put_String(channel->PortalName()); } else { resp->put_String(""); resp->put_String(""); } DEBUGLOG("RequestSignalInfo"); m_Queue->Add(resp); }
void cLiveStreamer::sendStatus(int status) { MsgPacket* packet = new MsgPacket(XVDR_STREAM_STATUS, XVDR_CHANNEL_STREAM); packet->put_U32(status); m_parent->QueueMessage(packet); }
void cLiveStreamer::sendStreamChange() { MsgPacket* resp = new MsgPacket(XVDR_STREAM_CHANGE, XVDR_CHANNEL_STREAM); DEBUGLOG("sendStreamChange"); cChannelCache cache; INFOLOG("Stored channel information in cache:"); for (std::list<cTSDemuxer*>::iterator i = m_Demuxers.begin(); i != m_Demuxers.end(); i++) { cache.AddStream(*(*i)); (*i)->info(); } cChannelCache::AddToCache(m_uid, cache); m_FilterMutex.Lock(); // reorder streams as preferred reorderStreams(m_LanguageIndex, m_LangStreamType); for (std::list<cTSDemuxer*>::iterator idx = m_Demuxers.begin(); idx != m_Demuxers.end(); idx++) { cTSDemuxer* stream = (*idx); if (stream == NULL) continue; int streamid = stream->GetPID(); resp->put_U32(streamid); switch(stream->GetContent()) { case cStreamInfo::scAUDIO: resp->put_String(stream->TypeName()); resp->put_String(stream->GetLanguage()); if(m_protocolVersion >= 5) { resp->put_U32(stream->GetChannels()); resp->put_U32(stream->GetSampleRate()); resp->put_U32(stream->GetBlockAlign()); resp->put_U32(stream->GetBitRate()); resp->put_U32(stream->GetBitsPerSample()); } break; case cStreamInfo::scVIDEO: resp->put_String(stream->TypeName()); resp->put_U32(stream->GetFpsScale()); resp->put_U32(stream->GetFpsRate()); resp->put_U32(stream->GetHeight()); resp->put_U32(stream->GetWidth()); resp->put_S64(stream->GetAspect() * 10000.0); break; case cStreamInfo::scSUBTITLE: resp->put_String(stream->TypeName()); resp->put_String(stream->GetLanguage()); resp->put_U32(stream->CompositionPageId()); resp->put_U32(stream->AncillaryPageId()); break; case cStreamInfo::scTELETEXT: resp->put_String(stream->TypeName()); break; default: break; } } m_FilterMutex.Unlock(); m_Queue->Add(resp); m_requestStreamChange = false; }
Packet* Demux::Read() { if(ConnectionLost() || Aborting()) { return NULL; } Packet* p = NULL; MsgPacket* pkt = NULL; m_lock.Lock(); if(m_queuelocked) { m_lock.Unlock(); return m_client->AllocatePacket(0); } if (m_buffer != NULL) { pkt = m_buffer->get(); if (pkt == NULL) { m_lock.Unlock(); m_cond.Wait(100); m_lock.Lock(); pkt = m_buffer->get(); } if (pkt != NULL) { pkt->rewind(); switch (pkt->getMsgID()) { case XVDR_STREAM_MUXPKT: { uint16_t id = pkt->get_U16(); int64_t pts = pkt->get_S64(); int64_t dts = pkt->get_S64(); uint32_t duration = pkt->get_U32(); uint32_t length = pkt->get_U32(); uint8_t* payload = pkt->consume(length); Stream& stream = m_streams[id]; if (stream.PhysicalId != id) { m_client->Log(DEBUG, "stream id %i not found", id); } else { p = m_client->AllocatePacket(length); m_client->SetPacketData(p, payload, stream.Index, dts, pts, duration); } break; } case XVDR_STREAM_CHANGE: { StreamChange(pkt); p = m_client->StreamChange(m_streams); break; } } } if (p == NULL) { p = m_client->AllocatePacket(0); } m_buffer->release(pkt); m_lock.Unlock(); return p; } bool bEmpty = m_queue.empty(); // empty queue -> wait for packet if (bEmpty) { m_lock.Unlock(); // request packets in timeshift mode if(m_timeshiftmode) { MsgPacket req(XVDR_CHANNELSTREAM_REQUEST, XVDR_CHANNEL_STREAM); if(!Session::TransmitMessage(&req)) return NULL; } m_cond.Wait(100); m_lock.Lock(); bEmpty = m_queue.empty(); } if (!bEmpty) { p = m_queue.front(); m_queue.pop(); } m_lock.Unlock(); if(p == NULL) { p = m_client->AllocatePacket(0); } return p; }
void cLiveStreamer::RequestSignalInfo() { // do not send (and pollute the client with) signal information // if we are paused if(IsPaused()) return; MsgPacket* resp = new MsgPacket(XVDR_STREAM_SIGNALINFO, XVDR_CHANNEL_STREAM); int DeviceNumber = m_Device->DeviceNumber() + 1; int Strength = 0; int Quality = 0; if(!TimeShiftMode()) { Strength = m_Device->SignalStrength(); Quality = m_Device->SignalQuality(); } resp->put_String(*cString::sprintf("%s #%d - %s", #if VDRVERSNUM < 10728 #warning "VDR versions < 1.7.28 do not support all features" "Unknown", DeviceNumber, "Unknown")); #else (const char*)m_Device->DeviceType(), DeviceNumber, (const char*)m_Device->DeviceName())); #endif // Quality: // 4 - NO LOCK // 3 - NO SYNC // 2 - NO VITERBI // 1 - NO CARRIER // 0 - NO SIGNAL if(TimeShiftMode()) { resp->put_String("TIMESHIFT"); } else if(Quality == -1) { resp->put_String("UNKNOWN (Incompatible device)"); Quality = 0; } else resp->put_String(*cString::sprintf("%s:%s:%s:%s:%s", (Quality > 4) ? "LOCKED" : "-", (Quality > 0) ? "SIGNAL" : "-", (Quality > 1) ? "CARRIER" : "-", (Quality > 2) ? "VITERBI" : "-", (Quality > 3) ? "SYNC" : "-")); resp->put_U32((Strength << 16 ) / 100); resp->put_U32((Quality << 16 ) / 100); resp->put_U32(0); resp->put_U32(0); DEBUGLOG("RequestSignalInfo"); m_Queue->Add(resp); }