OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/media/cast_remoting_sender.h" |
| 6 |
| 7 #include <map> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" |
| 11 #include "base/callback.h" |
| 12 #include "base/lazy_instance.h" |
| 13 #include "content/public/browser/browser_thread.h" |
| 14 #include "media/base/bind_to_current_loop.h" |
| 15 |
| 16 using content::BrowserThread; |
| 17 |
| 18 namespace { |
| 19 |
| 20 // Global map for looking-up CastRemotingSender instances by their |
| 21 // |rtp_stream_id|. |
| 22 using CastRemotingSenderMap = std::map<int32_t, CastRemotingSender*>; |
| 23 base::LazyInstance<CastRemotingSenderMap>::Leaky g_sender_map = |
| 24 LAZY_INSTANCE_INITIALIZER; |
| 25 |
| 26 } // namespace |
| 27 |
| 28 CastRemotingSender::CastRemotingSender(int32_t rtp_stream_id) |
| 29 : rtp_stream_id_(rtp_stream_id), binding_(this) { |
| 30 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 31 CastRemotingSender*& pointer_in_map = g_sender_map.Get()[rtp_stream_id_]; |
| 32 DCHECK(!pointer_in_map); |
| 33 pointer_in_map = this; |
| 34 } |
| 35 |
| 36 CastRemotingSender::~CastRemotingSender() { |
| 37 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 38 g_sender_map.Pointer()->erase(rtp_stream_id_); |
| 39 } |
| 40 |
| 41 // static |
| 42 void CastRemotingSender::FindAndBind( |
| 43 int32_t rtp_stream_id, |
| 44 mojo::ScopedDataPipeConsumerHandle pipe, |
| 45 media::mojom::RemotingDataStreamSenderRequest request, |
| 46 const base::Closure& error_callback) { |
| 47 // CastRemotingSender lives entirely on the IO thread, so trampoline if |
| 48 // necessary. |
| 49 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 50 BrowserThread::PostTask( |
| 51 BrowserThread::IO, FROM_HERE, |
| 52 base::Bind(&CastRemotingSender::FindAndBind, rtp_stream_id, |
| 53 base::Passed(&pipe), base::Passed(&request), |
| 54 // Using media::BindToCurrentLoop() so the |error_callback| |
| 55 // is trampolined back to the original thread. |
| 56 media::BindToCurrentLoop(error_callback))); |
| 57 return; |
| 58 } |
| 59 |
| 60 DCHECK(!error_callback.is_null()); |
| 61 |
| 62 // Look-up the CastRemotingSender instance by its |rtp_stream_id|. |
| 63 const auto it = g_sender_map.Pointer()->find(rtp_stream_id); |
| 64 if (it == g_sender_map.Pointer()->end()) { |
| 65 DLOG(ERROR) << "Cannot find CastRemotingSender instance by ID: " |
| 66 << rtp_stream_id; |
| 67 error_callback.Run(); |
| 68 return; |
| 69 } |
| 70 |
| 71 // Confirm that the CastRemotingSender isn't already bound to a message pipe. |
| 72 CastRemotingSender* const sender = it->second; |
| 73 if (sender->binding_.is_bound()) { |
| 74 DLOG(ERROR) << "Attempt to bind to CastRemotingSender a second time (id=" |
| 75 << rtp_stream_id << ")!"; |
| 76 error_callback.Run(); |
| 77 return; |
| 78 } |
| 79 |
| 80 DCHECK(sender->error_callback_.is_null()); |
| 81 sender->error_callback_ = error_callback; |
| 82 |
| 83 sender->pipe_ = std::move(pipe); |
| 84 sender->binding_.Bind(std::move(request)); |
| 85 sender->binding_.set_connection_error_handler( |
| 86 base::Bind(&base::Closure::Run, |
| 87 base::Unretained(&sender->error_callback_))); |
| 88 } |
| 89 |
| 90 void CastRemotingSender::ConsumeDataChunk(uint32_t offset, uint32_t size, |
| 91 uint32_t total_payload_size) { |
| 92 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 93 |
| 94 const void* buffer; |
| 95 uint32_t buffer_num_bytes = size; |
| 96 if (offset + size > total_payload_size || !pipe_.is_valid() || |
| 97 mojo::BeginReadDataRaw(pipe_.get(), &buffer, &buffer_num_bytes, |
| 98 MOJO_READ_DATA_FLAG_ALL_OR_NONE) != |
| 99 MOJO_RESULT_OK || |
| 100 buffer_num_bytes != size) { |
| 101 pipe_.reset(); |
| 102 binding_.Close(); |
| 103 error_callback_.Run(); |
| 104 return; |
| 105 } |
| 106 // If |total_payload_size| has changed, resize the data string. If it has not |
| 107 // changed, the following statement will be a no-op. |
| 108 next_frame_data_.resize(total_payload_size, '\0'); |
| 109 memcpy(&next_frame_data_.front() + offset, buffer, buffer_num_bytes); |
| 110 mojo::EndReadDataRaw(pipe_.get(), buffer_num_bytes); |
| 111 } |
| 112 |
| 113 void CastRemotingSender::SendFrame() { |
| 114 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 115 |
| 116 // TODO(miu): Merge with xjz's recent change, which implements this |
| 117 // functionality. |
| 118 NOTIMPLEMENTED(); // encoder_frame.data.swap(next_frame_data_) |
| 119 } |
| 120 |
| 121 void CastRemotingSender::CancelInFlightData() { |
| 122 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 123 |
| 124 // Note: Not calling clear(), in order to force a significant amount of memory |
| 125 // to be freed. |
| 126 std::string().swap(next_frame_data_); |
| 127 |
| 128 // TODO(miu): Merge with xjz's recent change, which implements this |
| 129 // functionality. |
| 130 NOTIMPLEMENTED(); // transport_->CancelSendingFrames(...); |
| 131 } |
OLD | NEW |