in_process_receiver.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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
17using media::cast::transport::CastTransportStatus;
18using media::cast::transport::UdpTransport;
19
20namespace media {
21namespace cast {
22
23InProcessReceiver::InProcessReceiver(
24    const scoped_refptr<CastEnvironment>& cast_environment,
25    const net::IPEndPoint& local_end_point,
26    const net::IPEndPoint& remote_end_point,
27    const AudioReceiverConfig& audio_config,
28    const VideoReceiverConfig& 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
36InProcessReceiver::~InProcessReceiver() {
37  Stop();
38}
39
40void InProcessReceiver::Start() {
41  cast_environment_->PostTask(CastEnvironment::MAIN,
42                              FROM_HERE,
43                              base::Bind(&InProcessReceiver::StartOnMainThread,
44                                         base::Unretained(this)));
45}
46
47void 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
61void 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
69void InProcessReceiver::DestroySoon() {
70  cast_environment_->PostTask(
71      CastEnvironment::MAIN,
72      FROM_HERE,
73      base::Bind(&InProcessReceiver::WillDestroyReceiver, base::Owned(this)));
74}
75
76void InProcessReceiver::UpdateCastTransportStatus(CastTransportStatus status) {
77  LOG_IF(ERROR, status == media::cast::transport::TRANSPORT_SOCKET_ERROR)
78      << "Transport socket error occurred.  InProcessReceiver is likely dead.";
79  VLOG(1) << "CastTransportStatus is now " << status;
80}
81
82void InProcessReceiver::StartOnMainThread() {
83  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
84
85  DCHECK(!transport_ && !cast_receiver_);
86  transport_.reset(
87      new UdpTransport(NULL,
88                       cast_environment_->GetTaskRunner(CastEnvironment::MAIN),
89                       local_end_point_,
90                       remote_end_point_,
91                       base::Bind(&InProcessReceiver::UpdateCastTransportStatus,
92                                  base::Unretained(this))));
93  cast_receiver_ = CastReceiver::Create(
94      cast_environment_, audio_config_, video_config_, transport_.get());
95
96  // TODO(hubbe): Make the cast receiver do this automatically.
97  transport_->StartReceiving(cast_receiver_->packet_receiver());
98
99  PullNextAudioFrame();
100  PullNextVideoFrame();
101}
102
103void InProcessReceiver::GotAudioFrame(scoped_ptr<AudioBus> audio_frame,
104                                      const base::TimeTicks& playout_time,
105                                      bool is_continuous) {
106  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
107  if (audio_frame.get()) {
108    // TODO(miu): Remove use of deprecated PcmAudioFrame and also pass
109    // |is_continuous| flag.
110    scoped_ptr<PcmAudioFrame> pcm_frame(new PcmAudioFrame());
111    pcm_frame->channels = audio_frame->channels();
112    pcm_frame->frequency = audio_config_.frequency;
113    pcm_frame->samples.resize(audio_frame->channels() * audio_frame->frames());
114    audio_frame->ToInterleaved(
115        audio_frame->frames(), sizeof(int16), &pcm_frame->samples.front());
116    OnAudioFrame(pcm_frame.Pass(), playout_time);
117  }
118  PullNextAudioFrame();
119}
120
121void InProcessReceiver::GotVideoFrame(
122    const scoped_refptr<VideoFrame>& video_frame,
123    const base::TimeTicks& render_time) {
124  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
125  OnVideoFrame(video_frame, render_time);
126  PullNextVideoFrame();
127}
128
129void InProcessReceiver::PullNextAudioFrame() {
130  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
131  cast_receiver_->frame_receiver()->GetRawAudioFrame(
132      base::Bind(&InProcessReceiver::GotAudioFrame,
133                 weak_factory_.GetWeakPtr()));
134}
135
136void InProcessReceiver::PullNextVideoFrame() {
137  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
138  cast_receiver_->frame_receiver()->GetRawVideoFrame(base::Bind(
139      &InProcessReceiver::GotVideoFrame, weak_factory_.GetWeakPtr()));
140}
141
142// static
143void InProcessReceiver::WillDestroyReceiver(InProcessReceiver* receiver) {
144  DCHECK(receiver->cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
145}
146
147}  // namespace cast
148}  // namespace media
149