av_streamer_proxy.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromecast/media/cma/ipc_streamer/av_streamer_proxy.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromecast/media/cma/base/coded_frame_provider.h" 11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chromecast/media/cma/base/decoder_buffer_base.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromecast/media/cma/ipc/media_memory_chunk.h" 13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chromecast/media/cma/ipc/media_message.h" 14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromecast/media/cma/ipc/media_message_fifo.h" 1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chromecast/media/cma/ipc/media_message_type.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.h" 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromecast { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AvStreamerProxy::AvStreamerProxy() 24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : is_running_(false), 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pending_read_(false), 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pending_av_data_(false), 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) weak_factory_(this), 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_this_(weak_factory_.GetWeakPtr()) { 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) thread_checker_.DetachFromThread(); 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AvStreamerProxy::~AvStreamerProxy() { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AvStreamerProxy::SetCodedFrameProvider( 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<CodedFrameProvider> frame_provider) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!frame_provider_); 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) frame_provider_.reset(frame_provider.release()); 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AvStreamerProxy::SetMediaMessageFifo( 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<MediaMessageFifo> fifo) { 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!fifo_); 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) fifo_.reset(fifo.release()); 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AvStreamerProxy::Start() { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!is_running_); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_running_ = true; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequestBufferIfNeeded(); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid AvStreamerProxy::StopAndFlush(const base::Closure& done_cb) { 5858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch is_running_ = false; 5958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 60ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch pending_av_data_ = false; 61ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch pending_audio_config_ = ::media::AudioDecoderConfig(); 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pending_video_config_ = ::media::VideoDecoderConfig(); 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pending_buffer_ = scoped_refptr<DecoderBufferBase>(); 64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch pending_read_ = false; 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame_provider_->Flush(done_cb); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AvStreamerProxy::OnFifoReadEvent() { 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Some enough space might have been released 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // to accommodate the pending data. 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pending_av_data_) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcessPendingData(); 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AvStreamerProxy::RequestBufferIfNeeded() { 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!is_running_ || pending_read_ || pending_av_data_) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |frame_provider_| is assumed to run on the same message loop. 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Add a BindToCurrentLoop if that's not the case in the future. 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pending_read_ = true; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame_provider_->Read(base::Bind(&AvStreamerProxy::OnNewBuffer, weak_this_)); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AvStreamerProxy::OnNewBuffer( 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const scoped_refptr<DecoderBufferBase>& buffer, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ::media::AudioDecoderConfig& audio_config, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ::media::VideoDecoderConfig& video_config) { 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) pending_read_ = false; 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buffer->end_of_stream()) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_running_ = false; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!pending_av_data_); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_av_data_ = true; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_buffer_ = buffer; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_audio_config_ = audio_config; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_video_config_ = video_config; 10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ProcessPendingData(); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void AvStreamerProxy::ProcessPendingData() { 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pending_audio_config_.IsValidConfig()) { 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!SendAudioDecoderConfig(pending_audio_config_)) 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_audio_config_ = ::media::AudioDecoderConfig(); 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pending_video_config_.IsValidConfig()) { 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!SendVideoDecoderConfig(pending_video_config_)) 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_video_config_ = ::media::VideoDecoderConfig(); 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_buffer_.get()) { 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!SendBuffer(pending_buffer_)) 126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return; 127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) pending_buffer_ = scoped_refptr<DecoderBufferBase>(); 128a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) pending_av_data_ = false; 131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::MessageLoopProxy::current()->PostTask( 132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) FROM_HERE, 133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Bind(&AvStreamerProxy::RequestBufferIfNeeded, weak_this_)); 134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 135b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 136b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool AvStreamerProxy::SendAudioDecoderConfig( 137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const ::media::AudioDecoderConfig& config) { 138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Create a dummy message to calculate first the message size. 139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<MediaMessage> dummy_msg( 140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) MediaMessage::CreateDummyMessage(AudioConfigMediaMsg)); 141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) AudioDecoderConfigMarshaller::Write(config, dummy_msg.get()); 142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 143a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Create the real message and write the actual content. 144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<MediaMessage> msg( 145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) MediaMessage::CreateMessage( 146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) AudioConfigMediaMsg, 147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::Bind(&MediaMessageFifo::ReserveMemory, 148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::Unretained(fifo_.get())), 149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) dummy_msg->content_size())); 150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!msg) 151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) AudioDecoderConfigMarshaller::Write(config, msg.get()); 154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return true; 155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AvStreamerProxy::SendVideoDecoderConfig( 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ::media::VideoDecoderConfig& config) { 159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Create a dummy message to calculate first the message size. 160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<MediaMessage> dummy_msg( 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) MediaMessage::CreateDummyMessage(VideoConfigMediaMsg)); 162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) VideoDecoderConfigMarshaller::Write(config, dummy_msg.get()); 163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Create the real message and write the actual content. 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<MediaMessage> msg( 1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MediaMessage::CreateMessage( 1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VideoConfigMediaMsg, 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&MediaMessageFifo::ReserveMemory, 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Unretained(fifo_.get())), 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dummy_msg->content_size())); 171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!msg) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) VideoDecoderConfigMarshaller::Write(config, msg.get()); 17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AvStreamerProxy::SendBuffer( 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<DecoderBufferBase>& buffer) { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create a dummy message to calculate first the message size. 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<MediaMessage> dummy_msg( 18258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) MediaMessage::CreateDummyMessage(FrameMediaMsg)); 18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DecoderBufferBaseMarshaller::Write(buffer, dummy_msg.get()); 18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Create the real message and write the actual content. 18658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scoped_ptr<MediaMessage> msg( 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MediaMessage::CreateMessage( 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FrameMediaMsg, 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&MediaMessageFifo::ReserveMemory, 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(fifo_.get())), 191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dummy_msg->content_size())); 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!msg) 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DecoderBufferBaseMarshaller::Write(buffer, msg.get()); 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace media 200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace chromecast 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)