| 1844 | } |
| 1845 | |
| 1846 | void RtmpClientStream::OnStopInternal() { |
| 1847 | if (_rtmpsock == NULL) { |
| 1848 | return CallOnStop(); |
| 1849 | } |
| 1850 | |
| 1851 | if (!_rtmpsock->Failed() && _chunk_stream_id != 0) { |
| 1852 | // SRS requires closeStream which is sent over this stream. |
| 1853 | butil::IOBuf req_buf1; |
| 1854 | { |
| 1855 | butil::IOBufAsZeroCopyOutputStream zc_stream(&req_buf1); |
| 1856 | AMFOutputStream ostream(&zc_stream); |
| 1857 | WriteAMFString(RTMP_AMF0_COMMAND_CLOSE_STREAM, &ostream); |
| 1858 | WriteAMFUint32(0, &ostream); |
| 1859 | WriteAMFNull(&ostream); |
| 1860 | CHECK(ostream.good()); |
| 1861 | } |
| 1862 | SocketMessagePtr<policy::RtmpUnsentMessage> msg1(new policy::RtmpUnsentMessage); |
| 1863 | msg1->header.message_length = req_buf1.size(); |
| 1864 | msg1->header.message_type = policy::RTMP_MESSAGE_COMMAND_AMF0; |
| 1865 | msg1->header.stream_id = _message_stream_id; |
| 1866 | msg1->chunk_stream_id = _chunk_stream_id; |
| 1867 | msg1->body = req_buf1; |
| 1868 | |
| 1869 | // Send deleteStream over the control stream. |
| 1870 | butil::IOBuf req_buf2; |
| 1871 | { |
| 1872 | butil::IOBufAsZeroCopyOutputStream zc_stream(&req_buf2); |
| 1873 | AMFOutputStream ostream(&zc_stream); |
| 1874 | WriteAMFString(RTMP_AMF0_COMMAND_DELETE_STREAM, &ostream); |
| 1875 | WriteAMFUint32(0, &ostream); |
| 1876 | WriteAMFNull(&ostream); |
| 1877 | WriteAMFUint32(_message_stream_id, &ostream); |
| 1878 | CHECK(ostream.good()); |
| 1879 | } |
| 1880 | policy::RtmpUnsentMessage* msg2 = policy::MakeUnsentControlMessage( |
| 1881 | policy::RTMP_MESSAGE_COMMAND_AMF0, req_buf2); |
| 1882 | msg1->next.reset(msg2); |
| 1883 | |
| 1884 | if (policy::WriteWithoutOvercrowded(_rtmpsock.get(), msg1) != 0) { |
| 1885 | if (errno != EFAILEDSOCKET) { |
| 1886 | PLOG(WARNING) << "Fail to send closeStream/deleteStream to " |
| 1887 | << _rtmpsock->remote_side() << "[" |
| 1888 | << _message_stream_id << "]"; |
| 1889 | // Close the connection to make sure the server-side knows the |
| 1890 | // closing event, however this may terminate other streams over |
| 1891 | // the connection as well. |
| 1892 | _rtmpsock->SetFailed(EFAILEDSOCKET, "Fail to send closeStream/deleteStream"); |
| 1893 | } |
| 1894 | } |
| 1895 | } |
| 1896 | policy::RtmpContext* ctx = |
| 1897 | static_cast<policy::RtmpContext*>(_rtmpsock->parsing_context()); |
| 1898 | if (ctx != NULL) { |
| 1899 | if (!ctx->RemoveMessageStream(this)) { |
| 1900 | // The stream is not registered yet. Is this normal? |
| 1901 | LOG(ERROR) << "Fail to remove stream_id=" << _message_stream_id; |
| 1902 | } |
| 1903 | } else { |
no test coverage detected