nsresult ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume) { NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread"); CMLOG("CacheClientSeek requested for aOffset [%lld] for decoder [%p]", aOffset, mDecoder); CloseChannel(); if (aResume) { NS_ASSERTION(mSuspendCount > 0, "Too many resumes!"); // No need to mess with the channel, since we're making a new one --mSuspendCount; } mOffset = aOffset; if (mSuspendCount > 0) { // Close the existing channel to force the channel to be recreated at // the correct offset upon resume. if (mChannel) { mIgnoreClose = true; CloseChannel(); } return NS_OK; } nsresult rv = RecreateChannel(); if (NS_FAILED(rv)) return rv; return OpenChannel(nullptr); }
void ChannelMediaResource::Suspend(bool aCloseImmediately) { NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread"); MediaDecoderOwner* owner = mDecoder->GetMediaOwner(); if (!owner) { // Shutting down; do nothing. return; } dom::HTMLMediaElement* element = owner->GetMediaElement(); if (!element) { // Shutting down; do nothing. return; } if (mChannel) { if (aCloseImmediately && mCacheStream.IsTransportSeekable()) { // Kill off our channel right now, but don't tell anyone about it. mIgnoreClose = true; CloseChannel(); element->DownloadSuspended(); } else if (mSuspendCount == 0) { { MutexAutoLock lock(mLock); mChannelStatistics->Stop(); } PossiblySuspend(); element->DownloadSuspended(); } } ++mSuspendCount; }
nsresult ChannelMediaResource::Close() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); mCacheStream.Close(); CloseChannel(); return NS_OK; }
void NetManager::ProcPendingClose() { std::deque<int32> vToClose; { AUTOLOCK(m_closingQueueLock); while (!m_closingQueue.empty()) { int32 nChannelID = m_closingQueue.front(); m_closingQueue.pop_front(); vToClose.push_back(nChannelID); } } for (auto itr = vToClose.begin(); itr != vToClose.end(); ++itr) { CloseChannel(*itr); } }
//析构函数 CChannelService::~CChannelService() { CloseChannel(true,false); return; }
//IPC 消息 LRESULT CChannelService::OnIPCMessage(WPARAM wParam, LPARAM lParam) { //提取数据 tagDataHead DataHead; tagIPCPacket IPCPacket; bool bSuccess=m_DataStorage.GetData(DataHead,&IPCPacket,sizeof(IPCPacket)); //效验数据 ASSERT(bSuccess==true); ASSERT(DataHead.wDataSize>=IPCPacketSize(IPCPacket)); ASSERT(DataHead.wDataSize==IPCPacket.Head.wDataSize+IPCPacketSize(IPCPacket)); if (DataHead.wDataSize<IPCPacketSize(IPCPacket)) return 0; if (DataHead.wDataSize!=IPCPacket.Head.wDataSize+IPCPacketSize(IPCPacket)) return 0; //处理数据 try { if (IPCPacket.Head.wMainCmdID==IPC_MIAN_IPC_KERNEL) { //内核消息 switch (IPCPacket.Head.wSubCmdID) { case IPC_SUB_IPC_CLIENT_CONNECT: //连接消息 { //处理通知 if (m_pIChannelEventSink!=NULL) m_pIChannelEventSink->OnChannelConnect(IPCPacket.hWndSend); //发送通知 CIPCSendCopyData SendCopyData; SendCopyData.SetClientHwnd(m_hWnd); SendCopyData.SetServerHwnd(IPCPacket.hWndSend); SendCopyData.SendData(IPC_MIAN_IPC_KERNEL,IPC_SUB_IPC_SERVER_ACCEPT); break; } case IPC_SUB_IPC_SERVER_ACCEPT: //应答消息 { //处理通知 if (m_pIChannelEventSink!=NULL) m_pIChannelEventSink->OnChannelAccept(IPCPacket.hWndSend); break; } case IPC_SUB_IPC_CLIENT_CLOSE: //关闭消息 { //关闭连接 CloseChannel(false,true); break; } default: ASSERT(0); } } else //外围消息 { if (m_pIChannelMessageSink!=NULL) { WORD wDataSize=IPCPacket.Head.wDataSize; m_pIChannelMessageSink->OnChannelMessage(&IPCPacket.Head,IPCPacket.cbBuffer,wDataSize,IPCPacket.hWndSend); } } } catch (...) { } return 0; }
void ChannelsManager::CloseAllChannels () { Q_FOREACH (auto ich, ChannelHandlers_.values ()) ich->CloseChannel (); }
nsresult ChannelMediaResource::OnStartRequest(nsIRequest* aRequest) { NS_ASSERTION(mChannel.get() == aRequest, "Wrong channel!"); MediaDecoderOwner* owner = mDecoder->GetMediaOwner(); NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE); dom::HTMLMediaElement* element = owner->GetMediaElement(); NS_ENSURE_TRUE(element, NS_ERROR_FAILURE); nsresult status; nsresult rv = aRequest->GetStatus(&status); NS_ENSURE_SUCCESS(rv, rv); if (element->ShouldCheckAllowOrigin()) { // If the request was cancelled by nsCORSListenerProxy due to failing // the CORS security check, send an error through to the media element. if (status == NS_ERROR_DOM_BAD_URI) { mDecoder->NetworkError(); return NS_ERROR_DOM_BAD_URI; } } nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(aRequest); bool seekable = false; if (hc) { uint32_t responseStatus = 0; hc->GetResponseStatus(&responseStatus); bool succeeded = false; hc->GetRequestSucceeded(&succeeded); if (!succeeded && NS_SUCCEEDED(status)) { // HTTP-level error (e.g. 4xx); treat this as a fatal network-level error. // We might get this on a seek. // (Note that lower-level errors indicated by NS_FAILED(status) are // handled in OnStopRequest.) // A 416 error should treated as EOF here... it's possible // that we don't get Content-Length, we read N bytes, then we // suspend and resume, the resume reopens the channel and we seek to // offset N, but there are no more bytes, so we get a 416 // "Requested Range Not Satisfiable". if (responseStatus == HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE) { // OnStopRequest will not be fired, so we need to do some of its // work here. mCacheStream.NotifyDataEnded(status); } else { mDecoder->NetworkError(); } // This disconnects our listener so we don't get any more data. We // certainly don't want an error page to end up in our cache! CloseChannel(); return NS_OK; } nsAutoCString ranges; hc->GetResponseHeader(NS_LITERAL_CSTRING("Accept-Ranges"), ranges); bool acceptsRanges = ranges.EqualsLiteral("bytes"); // True if this channel will not return an unbounded amount of data bool dataIsBounded = false; int64_t contentLength = -1; hc->GetContentLength(&contentLength); if (contentLength >= 0 && responseStatus == HTTP_OK_CODE) { // "OK" status means Content-Length is for the whole resource. // Since that's bounded, we know we have a finite-length resource. dataIsBounded = true; } if (mOffset == 0) { // Look for duration headers from known Ogg content systems. // In the case of multiple options for obtaining the duration // the order of precedence is: // 1) The Media resource metadata if possible (done by the decoder itself). // 2) Content-Duration message header. // 3) X-AMZ-Meta-Content-Duration. // 4) X-Content-Duration. // 5) Perform a seek in the decoder to find the value. nsAutoCString durationText; nsresult ec = NS_OK; rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("Content-Duration"), durationText); if (NS_FAILED(rv)) { rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-AMZ-Meta-Content-Duration"), durationText); } if (NS_FAILED(rv)) { rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-Content-Duration"), durationText); } // If there is a Content-Duration header with a valid value, record // the duration. if (NS_SUCCEEDED(rv)) { double duration = durationText.ToDouble(&ec); if (ec == NS_OK && duration >= 0) { mDecoder->SetDuration(duration); // We know the resource must be bounded. dataIsBounded = true; } } } // Assume Range requests have a bounded upper limit unless the // Content-Range header tells us otherwise. bool boundedSeekLimit = true; // Check response code for byte-range requests (seeking, chunk requests). if (!mByteRange.IsNull() && (responseStatus == HTTP_PARTIAL_RESPONSE_CODE)) { // Parse Content-Range header. int64_t rangeStart = 0; int64_t rangeEnd = 0; int64_t rangeTotal = 0; rv = ParseContentRangeHeader(hc, rangeStart, rangeEnd, rangeTotal); if (NS_FAILED(rv)) { // Content-Range header text should be parse-able. CMLOG("Error processing \'Content-Range' for " "HTTP_PARTIAL_RESPONSE_CODE: rv[%x] channel[%p] decoder[%p]", rv, hc.get(), mDecoder); mDecoder->NetworkError(); CloseChannel(); return NS_OK; } // Give some warnings if the ranges are unexpected. // XXX These could be error conditions. NS_WARN_IF_FALSE(mByteRange.mStart == rangeStart, "response range start does not match request"); NS_WARN_IF_FALSE(mOffset == rangeStart, "response range start does not match current offset"); NS_WARN_IF_FALSE(mByteRange.mEnd == rangeEnd, "response range end does not match request"); // Notify media cache about the length and start offset of data received. // Note: If aRangeTotal == -1, then the total bytes is unknown at this stage. // For now, tell the decoder that the stream is infinite. if (rangeTotal == -1) { boundedSeekLimit = false; } else { mCacheStream.NotifyDataLength(rangeTotal); } mCacheStream.NotifyDataStarted(rangeStart); mOffset = rangeStart; // We received 'Content-Range', so the server accepts range requests. acceptsRanges = true; } else if (((mOffset > 0) || !mByteRange.IsNull()) && (responseStatus == HTTP_OK_CODE)) { // If we get an OK response but we were seeking, or requesting a byte // range, then we have to assume that seeking doesn't work. We also need // to tell the cache that it's getting data for the start of the stream. mCacheStream.NotifyDataStarted(0); mOffset = 0; // The server claimed it supported range requests. It lied. acceptsRanges = false; } else if (mOffset == 0 && (responseStatus == HTTP_OK_CODE || responseStatus == HTTP_PARTIAL_RESPONSE_CODE)) { if (contentLength >= 0) { mCacheStream.NotifyDataLength(contentLength); } } // XXX we probably should examine the Content-Range header in case // the server gave us a range which is not quite what we asked for // If we get an HTTP_OK_CODE response to our byte range request, // and the server isn't sending Accept-Ranges:bytes then we don't // support seeking. seekable = responseStatus == HTTP_PARTIAL_RESPONSE_CODE || acceptsRanges; if (seekable && boundedSeekLimit) { // If range requests are supported, and we did not see an unbounded // upper range limit, we assume the resource is bounded. dataIsBounded = true; } mDecoder->SetInfinite(!dataIsBounded); } mDecoder->SetTransportSeekable(seekable); mCacheStream.SetTransportSeekable(seekable); { MutexAutoLock lock(mLock); mIsTransportSeekable = seekable; mChannelStatistics->Start(); } mReopenOnError = false; // If we are seeking to get metadata, because we are playing an OGG file, // ignore if the channel gets closed without us suspending it explicitly. We // don't want to tell the element that the download has finished whereas we // just happended to have reached the end of the media while seeking. mIgnoreClose = mSeekingForMetadata; if (mSuspendCount > 0) { // Re-suspend the channel if it needs to be suspended // No need to call PossiblySuspend here since the channel is // definitely in the right state for us in OnStartRequest. mChannel->Suspend(); mIgnoreResume = false; } // Fires an initial progress event and sets up the stall counter so stall events // fire if no download occurs within the required time frame. mDecoder->Progress(false); return NS_OK; }
void ChannelHandler::Leave (const QString& msg) { CM_->LeaveChannel (ChannelOptions_.ChannelName_.toLower (), msg); CloseChannel (); }
void stopRadio(){ DestroyAnalyzer(CHANNEL_RX); SetChannelState(CHANNEL_RX,0,0); CloseChannel(CHANNEL_RX); }