Home | History | Annotate | Download | only in utility
      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 "media/cast/test/utility/in_process_receiver.h"
      6 
      7 #include "base/bind_helpers.h"
      8 #include "base/synchronization/waitable_event.h"
      9 #include "base/time/time.h"
     10 #include "media/base/video_frame.h"
     11 #include "media/cast/cast_config.h"
     12 #include "media/cast/cast_environment.h"
     13 #include "media/cast/cast_receiver.h"
     14 #include "media/cast/transport/cast_transport_config.h"
     15 #include "media/cast/transport/transport/udp_transport.h"
     16 
     17 using media::cast::transport::CastTransportStatus;
     18 using media::cast::transport::UdpTransport;
     19 
     20 namespace media {
     21 namespace cast {
     22 
     23 InProcessReceiver::InProcessReceiver(
     24     const scoped_refptr<CastEnvironment>& cast_environment,
     25     const net::IPEndPoint& local_end_point,
     26     const net::IPEndPoint& remote_end_point,
     27     const FrameReceiverConfig& audio_config,
     28     const FrameReceiverConfig& video_config)
     29     : cast_environment_(cast_environment),
     30       local_end_point_(local_end_point),
     31       remote_end_point_(remote_end_point),
     32       audio_config_(audio_config),
     33       video_config_(video_config),
     34       weak_factory_(this) {}
     35 
     36 InProcessReceiver::~InProcessReceiver() {
     37   Stop();
     38 }
     39 
     40 void InProcessReceiver::Start() {
     41   cast_environment_->PostTask(CastEnvironment::MAIN,
     42                               FROM_HERE,
     43                               base::Bind(&InProcessReceiver::StartOnMainThread,
     44                                          base::Unretained(this)));
     45 }
     46 
     47 void InProcessReceiver::Stop() {
     48   base::WaitableEvent event(false, false);
     49   if (cast_environment_->CurrentlyOn(CastEnvironment::MAIN)) {
     50     StopOnMainThread(&event);
     51   } else {
     52     cast_environment_->PostTask(CastEnvironment::MAIN,
     53                                 FROM_HERE,
     54                                 base::Bind(&InProcessReceiver::StopOnMainThread,
     55                                            base::Unretained(this),
     56                                            &event));
     57     event.Wait();
     58   }
     59 }
     60 
     61 void InProcessReceiver::StopOnMainThread(base::WaitableEvent* event) {
     62   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     63   cast_receiver_.reset(NULL);
     64   transport_.reset(NULL);
     65   weak_factory_.InvalidateWeakPtrs();
     66   event->Signal();
     67 }
     68 
     69 void InProcessReceiver::UpdateCastTransportStatus(CastTransportStatus status) {
     70   LOG_IF(ERROR, status == media::cast::transport::TRANSPORT_SOCKET_ERROR)
     71       << "Transport socket error occurred.  InProcessReceiver is likely dead.";
     72   VLOG(1) << "CastTransportStatus is now " << status;
     73 }
     74 
     75 void InProcessReceiver::StartOnMainThread() {
     76   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     77 
     78   DCHECK(!transport_ && !cast_receiver_);
     79   transport_.reset(
     80       new UdpTransport(NULL,
     81                        cast_environment_->GetTaskRunner(CastEnvironment::MAIN),
     82                        local_end_point_,
     83                        remote_end_point_,
     84                        base::Bind(&InProcessReceiver::UpdateCastTransportStatus,
     85                                   base::Unretained(this))));
     86   cast_receiver_ = CastReceiver::Create(
     87       cast_environment_, audio_config_, video_config_, transport_.get());
     88 
     89   // TODO(hubbe): Make the cast receiver do this automatically.
     90   transport_->StartReceiving(cast_receiver_->packet_receiver());
     91 
     92   PullNextAudioFrame();
     93   PullNextVideoFrame();
     94 }
     95 
     96 void InProcessReceiver::GotAudioFrame(scoped_ptr<AudioBus> audio_frame,
     97                                       const base::TimeTicks& playout_time,
     98                                       bool is_continuous) {
     99   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    100   if (audio_frame.get())
    101     OnAudioFrame(audio_frame.Pass(), playout_time, is_continuous);
    102   PullNextAudioFrame();
    103 }
    104 
    105 void InProcessReceiver::GotVideoFrame(
    106     const scoped_refptr<VideoFrame>& video_frame,
    107     const base::TimeTicks& playout_time,
    108     bool is_continuous) {
    109   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    110   if (video_frame)
    111     OnVideoFrame(video_frame, playout_time, is_continuous);
    112   PullNextVideoFrame();
    113 }
    114 
    115 void InProcessReceiver::PullNextAudioFrame() {
    116   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    117   cast_receiver_->RequestDecodedAudioFrame(
    118       base::Bind(&InProcessReceiver::GotAudioFrame,
    119                  weak_factory_.GetWeakPtr()));
    120 }
    121 
    122 void InProcessReceiver::PullNextVideoFrame() {
    123   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    124   cast_receiver_->RequestDecodedVideoFrame(base::Bind(
    125       &InProcessReceiver::GotVideoFrame, weak_factory_.GetWeakPtr()));
    126 }
    127 
    128 }  // namespace cast
    129 }  // namespace media
    130