1 // Copyright 2014 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 "content/renderer/media/aec_dump_message_filter.h" 6 7 #include "base/message_loop/message_loop_proxy.h" 8 #include "content/common/media/aec_dump_messages.h" 9 #include "content/renderer/media/webrtc_logging.h" 10 #include "ipc/ipc_logging.h" 11 #include "ipc/ipc_sender.h" 12 13 namespace { 14 const int kInvalidDelegateId = -1; 15 } 16 17 namespace content { 18 19 AecDumpMessageFilter* AecDumpMessageFilter::g_filter = NULL; 20 21 AecDumpMessageFilter::AecDumpMessageFilter( 22 const scoped_refptr<base::MessageLoopProxy>& io_message_loop, 23 const scoped_refptr<base::MessageLoopProxy>& main_message_loop) 24 : sender_(NULL), 25 delegate_id_counter_(0), 26 io_message_loop_(io_message_loop), 27 main_message_loop_(main_message_loop) { 28 DCHECK(!g_filter); 29 g_filter = this; 30 } 31 32 AecDumpMessageFilter::~AecDumpMessageFilter() { 33 DCHECK_EQ(g_filter, this); 34 g_filter = NULL; 35 } 36 37 // static 38 scoped_refptr<AecDumpMessageFilter> AecDumpMessageFilter::Get() { 39 return g_filter; 40 } 41 42 void AecDumpMessageFilter::AddDelegate( 43 AecDumpMessageFilter::AecDumpDelegate* delegate) { 44 DCHECK(main_message_loop_->BelongsToCurrentThread()); 45 DCHECK(delegate); 46 DCHECK_EQ(kInvalidDelegateId, GetIdForDelegate(delegate)); 47 48 int id = delegate_id_counter_++; 49 delegates_[id] = delegate; 50 51 io_message_loop_->PostTask( 52 FROM_HERE, 53 base::Bind( 54 &AecDumpMessageFilter::RegisterAecDumpConsumer, 55 this, 56 id)); 57 } 58 59 void AecDumpMessageFilter::RemoveDelegate( 60 AecDumpMessageFilter::AecDumpDelegate* delegate) { 61 DCHECK(main_message_loop_->BelongsToCurrentThread()); 62 DCHECK(delegate); 63 64 int id = GetIdForDelegate(delegate); 65 DCHECK_NE(kInvalidDelegateId, id); 66 delegates_.erase(id); 67 68 io_message_loop_->PostTask( 69 FROM_HERE, 70 base::Bind( 71 &AecDumpMessageFilter::UnregisterAecDumpConsumer, 72 this, 73 id)); 74 } 75 76 void AecDumpMessageFilter::Send(IPC::Message* message) { 77 DCHECK(io_message_loop_->BelongsToCurrentThread()); 78 if (sender_) 79 sender_->Send(message); 80 else 81 delete message; 82 } 83 84 void AecDumpMessageFilter::RegisterAecDumpConsumer(int id) { 85 Send(new AecDumpMsg_RegisterAecDumpConsumer(id)); 86 } 87 88 void AecDumpMessageFilter::UnregisterAecDumpConsumer(int id) { 89 Send(new AecDumpMsg_UnregisterAecDumpConsumer(id)); 90 } 91 92 bool AecDumpMessageFilter::OnMessageReceived(const IPC::Message& message) { 93 DCHECK(io_message_loop_->BelongsToCurrentThread()); 94 bool handled = true; 95 IPC_BEGIN_MESSAGE_MAP(AecDumpMessageFilter, message) 96 IPC_MESSAGE_HANDLER(AecDumpMsg_EnableAecDump, OnEnableAecDump) 97 IPC_MESSAGE_HANDLER(AecDumpMsg_DisableAecDump, OnDisableAecDump) 98 IPC_MESSAGE_UNHANDLED(handled = false) 99 IPC_END_MESSAGE_MAP() 100 return handled; 101 } 102 103 void AecDumpMessageFilter::OnFilterAdded(IPC::Sender* sender) { 104 DCHECK(io_message_loop_->BelongsToCurrentThread()); 105 sender_ = sender; 106 } 107 108 void AecDumpMessageFilter::OnFilterRemoved() { 109 DCHECK(io_message_loop_->BelongsToCurrentThread()); 110 111 // Once removed, a filter will not be used again. At this time the 112 // observer must be notified so it releases its reference. 113 OnChannelClosing(); 114 } 115 116 void AecDumpMessageFilter::OnChannelClosing() { 117 DCHECK(io_message_loop_->BelongsToCurrentThread()); 118 sender_ = NULL; 119 main_message_loop_->PostTask( 120 FROM_HERE, 121 base::Bind( 122 &AecDumpMessageFilter::DoChannelClosingOnDelegates, 123 this)); 124 } 125 126 void AecDumpMessageFilter::OnEnableAecDump( 127 int id, 128 IPC::PlatformFileForTransit file_handle) { 129 DCHECK(io_message_loop_->BelongsToCurrentThread()); 130 main_message_loop_->PostTask( 131 FROM_HERE, 132 base::Bind( 133 &AecDumpMessageFilter::DoEnableAecDump, 134 this, 135 id, 136 file_handle)); 137 } 138 139 void AecDumpMessageFilter::OnDisableAecDump() { 140 DCHECK(io_message_loop_->BelongsToCurrentThread()); 141 main_message_loop_->PostTask( 142 FROM_HERE, 143 base::Bind( 144 &AecDumpMessageFilter::DoDisableAecDump, 145 this)); 146 } 147 148 void AecDumpMessageFilter::DoEnableAecDump( 149 int id, 150 IPC::PlatformFileForTransit file_handle) { 151 DCHECK(main_message_loop_->BelongsToCurrentThread()); 152 DelegateMap::iterator it = delegates_.find(id); 153 if (it != delegates_.end()) { 154 it->second->OnAecDumpFile(file_handle); 155 } else { 156 // Delegate has been removed, we must close the file. 157 base::File file = IPC::PlatformFileForTransitToFile(file_handle); 158 DCHECK(file.IsValid()); 159 file.Close(); 160 } 161 } 162 163 void AecDumpMessageFilter::DoDisableAecDump() { 164 DCHECK(main_message_loop_->BelongsToCurrentThread()); 165 for (DelegateMap::iterator it = delegates_.begin(); 166 it != delegates_.end(); ++it) { 167 it->second->OnDisableAecDump(); 168 } 169 } 170 171 void AecDumpMessageFilter::DoChannelClosingOnDelegates() { 172 DCHECK(main_message_loop_->BelongsToCurrentThread()); 173 for (DelegateMap::iterator it = delegates_.begin(); 174 it != delegates_.end(); ++it) { 175 it->second->OnIpcClosing(); 176 } 177 delegates_.clear(); 178 } 179 180 int AecDumpMessageFilter::GetIdForDelegate( 181 AecDumpMessageFilter::AecDumpDelegate* delegate) { 182 DCHECK(main_message_loop_->BelongsToCurrentThread()); 183 for (DelegateMap::iterator it = delegates_.begin(); 184 it != delegates_.end(); ++it) { 185 if (it->second == delegate) 186 return it->first; 187 } 188 return kInvalidDelegateId; 189 } 190 191 } // namespace content 192