Music Hub  ..
A session-wide music playback service
server.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Canonical Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
17  */
18 
19 #include <core/media/service.h>
20 #include <core/media/player.h>
21 #include <core/media/track_list.h>
22 
26 
27 #include <hybris/media/media_codec_layer.h>
28 
29 #include <core/posix/signal.h>
30 
31 #include <iostream>
32 
33 namespace media = core::ubuntu::media;
34 
35 using namespace std;
36 
37 namespace
38 {
39 void logger_init()
40 {
41  const char *level = ::getenv("MH_LOG_LEVEL");
42  // Default level is kInfo
43  media::Logger::Severity severity{media::Logger::Severity::kInfo};
44  if (level)
45  {
46  if (strcmp(level, "trace") == 0)
47  severity = media::Logger::Severity::kTrace;
48  else if (strcmp(level, "debug") == 0)
49  severity = media::Logger::Severity::kDebug;
50  else if (strcmp(level, "info") == 0)
51  severity = media::Logger::Severity::kInfo;
52  else if (strcmp(level, "warning") == 0)
53  severity = media::Logger::Severity::kWarning;
54  else if (strcmp(level, "error") == 0)
55  severity = media::Logger::Severity::kError;
56  else if (strcmp(level, "fatal") == 0)
57  severity = media::Logger::Severity::kFatal;
58  else
59  std::cerr << "Invalid log level \"" << level
60  << "\", setting to info. Valid options: [trace, debug, info, warning, error, fatal]."
61  << std::endl;
62  }
63  else
64  std::cout << "Using default log level: info" << std::endl;
65 
66  media::Log().Init(severity);
67  cout << "Log level: " << severity << std::endl;
68 }
69 
70 // All platform-specific initialization routines go here.
71 void platform_init()
72 {
74  switch (b)
75  {
76  case media::AVBackend::Backend::hybris:
77  MH_DEBUG("Found hybris backend");
78  decoding_service_init();
79  break;
80  case media::AVBackend::Backend::mir:
81  MH_DEBUG("Found mir backend");
82  break;
83  case media::AVBackend::Backend::none:
84  MH_WARNING("No video backend selected. Video functionality won't work.");
85  break;
86  default:
87  MH_INFO("Invalid or no A/V backend specified, using \"hybris\" as a default.");
88  decoding_service_init();
89  }
90 }
91 }
92 
93 int main()
94 {
95  auto trap = core::posix::trap_signals_for_all_subsequent_threads(
96  {
97  core::posix::Signal::sig_int,
98  core::posix::Signal::sig_term
99  });
100 
101  trap->signal_raised().connect([trap](core::posix::Signal)
102  {
103  trap->stop();
104  });
105 
106  logger_init();
107 
108  // Init platform-specific functionality.
109  platform_init();
110 
111  // We keep track of our state.
112  bool shutdown_requested{false};
113 
114  // Our helper for connecting to external services.
116 
117  // We move communication with all external services to its own worker thread
118  // to keep the actual service thread free from such operations.
119  std::thread external_services_worker
120  {
121  // We keep on running until shutdown has been explicitly requested.
122  // All exceptions thrown on this thread are caught, and reported to
123  // the terminal for post-mortem debugging purposes.
124  [&shutdown_requested, &external_services]()
125  {
126  while (not shutdown_requested)
127  {
128  try
129  {
130  // Blocking call to the underlying reactor implementation.
131  // Only returns cleanly when explicitly stopped.
132  external_services.io_service.run();
133  }
134  catch (const std::exception& e)
135  {
136  std::cerr << "Error while executing the underlying io_service: " << e.what() << std::endl;
137  }
138  catch (...)
139  {
140  std::cerr << "Error while executing the underlying io_service." << std::endl;
141  }
142  }
143  }
144  };
145 
146  // Our common player store instance for tracking player instances.
147  auto player_store = std::make_shared<media::HashedKeyedPlayerStore>();
148  // We assemble the configuration for executing the service now.
149  media::ServiceImplementation::Configuration service_config
150  {
151  std::make_shared<media::HashedKeyedPlayerStore>(),
152  external_services
153  };
154 
155  auto impl = std::make_shared<media::ServiceImplementation>(media::ServiceImplementation::Configuration
156  {
157  player_store,
158  external_services
159  });
160 
161  auto skeleton = std::make_shared<media::ServiceSkeleton>(media::ServiceSkeleton::Configuration
162  {
163  impl,
164  player_store,
165  external_services,
166  nullptr
167  });
168 
169  std::thread service_worker
170  {
171  [&shutdown_requested, skeleton]()
172  {
173  while (not shutdown_requested)
174  {
175  try
176  {
177  skeleton->run();
178  }
179  catch (const std::exception& e)
180  {
181  std::cerr << "Recoverable error while executing the service: " << e.what() << std::endl;
182  }
183  catch (...)
184  {
185  std::cerr << "Recoverable error while executing the service." << std::endl;
186  }
187  }
188  }
189  };
190 
191  // We block on waiting for signals telling us to gracefully shutdown.
192  // Incoming signals are handled in a lambda connected to signal_raised()
193  // which is setup at the beginning of main(...).
194  trap->run();
195 
196  // Inform our workers that we should shutdown gracefully
197  shutdown_requested = true;
198 
199  // And stop execution of helper and actual service.
200  skeleton->stop();
201 
202  if (service_worker.joinable())
203  service_worker.join();
204 
205  external_services.stop();
206 
207  if (external_services_worker.joinable())
208  external_services_worker.join();
209 
210  return 0;
211 }
Logger & Log()
Definition: logger.cpp:151
virtual void Init(const core::ubuntu::media::Logger::Severity &severity=core::ubuntu::media::Logger::Severity::kWarning)=0
#define MH_INFO(...)
Definition: logger.h:125
STL namespace.
#define MH_DEBUG(...)
Definition: logger.h:123
#define MH_WARNING(...)
Definition: logger.h:127
static Backend get_backend_type()
Returns the type of audio/video decoding/encoding backend being used.
Definition: backend.cpp:26
int main()
Definition: server.cpp:93