1 /*
2 * This file is part of Wireless Display Software for Linux OS
3 *
4 * Copyright (C) 2014 Intel Corporation.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 */
21
22 #include "libwds/public/sink.h"
23
24 #include "libwds/common/message_handler.h"
25 #include "libwds/common/rtsp_input_handler.h"
26 #include "libwds/public/wds_export.h"
27 #include "libwds/rtsp/pause.h"
28 #include "libwds/rtsp/play.h"
29 #include "libwds/rtsp/teardown.h"
30 #include "libwds/rtsp/triggermethod.h"
31 #include "libwds/public/media_manager.h"
32 #include "libwds/sink/cap_negotiation_state.h"
33 #include "libwds/sink/init_state.h"
34 #include "libwds/sink/session_state.h"
35 #include "libwds/sink/streaming_state.h"
36
37 namespace wds {
38 using rtsp::Message;
39 using rtsp::Request;
40 using rtsp::Reply;
41
42 namespace {
43
44 // todo: check mandatory parameters for each message
InitializeRequestId(Request * request)45 bool InitializeRequestId(Request* request) {
46 Request::ID id = Request::UNKNOWN;
47 switch(request->method()) {
48 case Request::MethodOptions:
49 id = Request::M1;
50 break;
51 case Request::MethodGetParameter:
52 if (auto payload = rtsp::ToGetParameterPayload(request->payload())) {
53 if (!payload->properties().empty())
54 id = Request::M3;
55 } else {
56 id = Request::M16;
57 }
58 break;
59 case Request::MethodSetParameter:
60 if (auto payload = rtsp::ToPropertyMapPayload(request->payload())) {
61 if (payload->HasProperty(rtsp::PresentationURLPropertyType))
62 id = Request::M4;
63 else if (payload->HasProperty(rtsp::AVFormatChangeTimingPropertyType))
64 id = Request::M4;
65 else if (payload->HasProperty(rtsp::TriggerMethodPropertyType))
66 id = Request::M5;
67 break;
68 }
69 default:
70 WDS_ERROR("Failed to identify the received message");
71 return false;
72 }
73
74 request->set_id(id);
75 return true;
76 }
77
78 }
79
80 class SinkStateMachine : public MessageSequenceHandler {
81 public:
SinkStateMachine(const InitParams & init_params)82 SinkStateMachine(const InitParams& init_params)
83 : MessageSequenceHandler(init_params),
84 keep_alive_timer_(0) {
85 auto m6_handler = make_ptr(new sink::M6Handler(init_params, keep_alive_timer_));
86 auto m16_handler = make_ptr(new sink::M16Handler(init_params, keep_alive_timer_));
87 AddSequencedHandler(make_ptr(new sink::InitState(init_params)));
88 AddSequencedHandler(make_ptr(new sink::CapNegotiationState(init_params)));
89 AddSequencedHandler(make_ptr(new sink::SessionState(init_params, m6_handler, m16_handler)));
90 AddSequencedHandler(make_ptr(new sink::StreamingState(init_params, m16_handler)));
91 }
92
SinkStateMachine(Peer::Delegate * sender,SinkMediaManager * mng)93 SinkStateMachine(Peer::Delegate* sender, SinkMediaManager* mng)
94 : SinkStateMachine({sender, mng, this}) {}
95
96 private:
97 unsigned keep_alive_timer_;
98 };
99
100 class SinkImpl final : public Sink, public RTSPInputHandler, public MessageHandler::Observer {
101 public:
102 SinkImpl(Delegate* delegate, SinkMediaManager* mng);
103
104 private:
105 // Sink implementation.
106 void Start() override;
107 void Reset() override;
108 void RTSPDataReceived(const std::string& message) override;
109 bool Teardown() override;
110 bool Play() override;
111 bool Pause() override;
112
113 // RTSPInputHandler
114 void MessageParsed(std::unique_ptr<Message> message) override;
115
116 // public MessageHandler::Observer
117 void OnCompleted(MessageHandlerPtr handler) override;
118 void OnError(MessageHandlerPtr handler) override;
119 void OnTimerEvent(unsigned timer_id) override;
120
121 bool HandleCommand(std::unique_ptr<Message> command);
122
123 template <class WfdMessage, Request::ID id>
124 std::unique_ptr<Message> CreateCommand();
125
126 void ResetAndTeardownMedia();
127
128 std::shared_ptr<SinkStateMachine> state_machine_;
129 Delegate* delegate_;
130 SinkMediaManager* manager_;
131 };
132
SinkImpl(Delegate * delegate,SinkMediaManager * mng)133 SinkImpl::SinkImpl(Delegate* delegate, SinkMediaManager* mng)
134 : state_machine_(new SinkStateMachine({delegate, mng, this})),
135 delegate_(delegate),
136 manager_(mng) {
137 }
138
Start()139 void SinkImpl::Start() {
140 state_machine_->Start();
141 }
142
Reset()143 void SinkImpl::Reset() {
144 state_machine_->Reset();
145 }
146
RTSPDataReceived(const std::string & message)147 void SinkImpl::RTSPDataReceived(const std::string& message) {
148 AddInput(message);
149 }
150
151 template <class WfdMessage, Request::ID id>
CreateCommand()152 std::unique_ptr<Message> SinkImpl::CreateCommand() {
153 auto message = new WfdMessage(manager_->GetPresentationUrl());
154 message->header().set_session(manager_->GetSessionId());
155 message->header().set_cseq(delegate_->GetNextCSeq());
156 message->set_id(id);
157 return std::unique_ptr<Message>(message);
158 }
159
HandleCommand(std::unique_ptr<Message> command)160 bool SinkImpl::HandleCommand(std::unique_ptr<Message> command) {
161 if (manager_->GetSessionId().empty() ||
162 manager_->GetPresentationUrl().empty())
163 return false;
164
165 if (!state_machine_->CanSend(command.get()))
166 return false;
167 state_machine_->Send(std::move(command));
168 return true;
169 }
170
Teardown()171 bool SinkImpl::Teardown() {
172 return HandleCommand(CreateCommand<rtsp::Teardown, Request::M8>());
173 }
174
Play()175 bool SinkImpl::Play() {
176 return HandleCommand(CreateCommand<rtsp::Play, Request::M7>());
177 }
178
Pause()179 bool SinkImpl::Pause() {
180 return HandleCommand(CreateCommand<rtsp::Pause, Request::M9>());
181 }
182
MessageParsed(std::unique_ptr<Message> message)183 void SinkImpl::MessageParsed(std::unique_ptr<Message> message) {
184 if (message->is_request() && !InitializeRequestId(ToRequest(message.get()))) {
185 WDS_ERROR("Cannot identify the received message");
186 return;
187 }
188 if (!state_machine_->CanHandle(message.get())) {
189 WDS_ERROR("Cannot handle the received message with Id: %d", ToRequest(message.get())->id());
190 return;
191 }
192 state_machine_->Handle(std::move(message));
193 }
194
ResetAndTeardownMedia()195 void SinkImpl::ResetAndTeardownMedia() {
196 manager_->Teardown();
197 state_machine_->Reset();
198 }
199
OnCompleted(MessageHandlerPtr handler)200 void SinkImpl::OnCompleted(MessageHandlerPtr handler) {
201 assert(handler == state_machine_);
202 ResetAndTeardownMedia();
203 }
204
OnError(MessageHandlerPtr handler)205 void SinkImpl::OnError(MessageHandlerPtr handler) {
206 assert(handler == state_machine_);
207 ResetAndTeardownMedia();
208 }
209
OnTimerEvent(unsigned timer_id)210 void SinkImpl::OnTimerEvent(unsigned timer_id) {
211 if (state_machine_->HandleTimeoutEvent(timer_id))
212 state_machine_->Reset();
213 }
214
Create(Delegate * delegate,SinkMediaManager * mng)215 Sink* Sink::Create(Delegate* delegate, SinkMediaManager* mng) {
216 return new SinkImpl(delegate, mng);
217 }
218
219 } // namespace wds
220