| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <math.h> | 5 #include <math.h> |
| 6 #include <memory> | 6 #include <memory> |
| 7 | 7 |
| 8 #include "mojo/public/c/system/main.h" | 8 #include "mojo/public/c/system/main.h" |
| 9 #include "mojo/public/cpp/application/application_impl_base.h" | 9 #include "mojo/public/cpp/application/application_impl_base.h" |
| 10 #include "mojo/public/cpp/application/connect.h" | 10 #include "mojo/public/cpp/application/connect.h" |
| 11 #include "mojo/public/cpp/application/run_application.h" | 11 #include "mojo/public/cpp/application/run_application.h" |
| 12 #include "mojo/public/cpp/utility/run_loop.h" | 12 #include "mojo/public/cpp/utility/run_loop.h" |
| 13 #include "mojo/services/media/audio/interfaces/audio_server.mojom.h" | 13 #include "mojo/services/media/audio/interfaces/audio_server.mojom.h" |
| 14 #include "mojo/services/media/audio/interfaces/audio_track.mojom.h" | 14 #include "mojo/services/media/audio/interfaces/audio_track.mojom.h" |
| 15 #include "mojo/services/media/common/cpp/circular_buffer_media_pipe_adapter.h" | 15 #include "mojo/services/media/common/cpp/circular_buffer_media_pipe_adapter.h" |
| 16 #include "mojo/services/media/common/cpp/linear_transform.h" | 16 #include "mojo/services/media/common/cpp/linear_transform.h" |
| 17 #include "mojo/services/media/common/cpp/local_time.h" | 17 #include "mojo/services/media/common/cpp/local_time.h" |
| 18 #include "mojo/services/media/common/interfaces/timelines.mojom.h" | 18 #include "mojo/services/media/common/interfaces/timelines.mojom.h" |
| 19 #include "mojo/services/media/core/interfaces/media_renderer.mojom.h" |
| 19 | 20 |
| 20 namespace mojo { | 21 namespace mojo { |
| 21 namespace media { | 22 namespace media { |
| 22 namespace audio { | 23 namespace audio { |
| 23 namespace examples { | 24 namespace examples { |
| 24 | 25 |
| 25 static constexpr uint32_t SAMP_FREQ = 48000; | 26 static constexpr uint32_t SAMP_FREQ = 48000; |
| 26 static constexpr uint32_t CHUNK_USEC = 10000; | 27 static constexpr uint32_t CHUNK_USEC = 10000; |
| 27 static constexpr uint32_t BUF_LO_WATER_USEC = 500000; | 28 static constexpr uint32_t BUF_LO_WATER_USEC = 500000; |
| 28 static constexpr uint32_t BUF_HI_WATER_USEC = BUF_LO_WATER_USEC | 29 static constexpr uint32_t BUF_HI_WATER_USEC = BUF_LO_WATER_USEC |
| (...skipping 16 matching lines...) Expand all Loading... |
| 45 | 46 |
| 46 private: | 47 private: |
| 47 void GenerateToneCbk(MediaResult res); | 48 void GenerateToneCbk(MediaResult res); |
| 48 void PlayTone(double freq_hz, double amplitude, double duration_sec); | 49 void PlayTone(double freq_hz, double amplitude, double duration_sec); |
| 49 void PostShutdown(); | 50 void PostShutdown(); |
| 50 void Shutdown(); | 51 void Shutdown(); |
| 51 void OnConnectionError(const std::string& connection_name); | 52 void OnConnectionError(const std::string& connection_name); |
| 52 | 53 |
| 53 AudioServerPtr audio_server_; | 54 AudioServerPtr audio_server_; |
| 54 AudioTrackPtr audio_track_; | 55 AudioTrackPtr audio_track_; |
| 56 MediaRendererPtr media_renderer_; |
| 55 TimelineConsumerPtr timeline_consumer_; | 57 TimelineConsumerPtr timeline_consumer_; |
| 56 std::unique_ptr<CircularBufferMediaPipeAdapter> audio_pipe_; | 58 std::unique_ptr<CircularBufferMediaPipeAdapter> audio_pipe_; |
| 57 | 59 |
| 58 bool clock_started_ = false; | 60 bool clock_started_ = false; |
| 59 uint64_t media_time_ = 0; | 61 uint64_t media_time_ = 0; |
| 60 double freq_hz_ = 440.0; | 62 double freq_hz_ = 440.0; |
| 61 double amplitude_ = 1.0; | 63 double amplitude_ = 1.0; |
| 62 bool shutting_down_ = false; | 64 bool shutting_down_ = false; |
| 63 }; | 65 }; |
| 64 | 66 |
| 65 void PlayToneApp::OnQuit() { | 67 void PlayToneApp::OnQuit() { |
| 66 timeline_consumer_.reset(); | 68 timeline_consumer_.reset(); |
| 67 audio_pipe_.reset(); | 69 audio_pipe_.reset(); |
| 68 audio_track_.reset(); | 70 audio_track_.reset(); |
| 71 media_renderer_.reset(); |
| 69 audio_server_.reset(); | 72 audio_server_.reset(); |
| 70 } | 73 } |
| 71 | 74 |
| 72 void PlayToneApp::OnInitialize() { | 75 void PlayToneApp::OnInitialize() { |
| 73 mojo::ConnectToService(shell(), "mojo:audio_server", | 76 mojo::ConnectToService(shell(), "mojo:audio_server", |
| 74 GetProxy(&audio_server_)); | 77 GetProxy(&audio_server_)); |
| 75 audio_server_.set_connection_error_handler([this]() { | 78 audio_server_.set_connection_error_handler([this]() { |
| 76 OnConnectionError("audio_server"); | 79 OnConnectionError("audio_server"); |
| 77 }); | 80 }); |
| 78 | 81 |
| 79 audio_server_->CreateTrack(GetProxy(&audio_track_)); | 82 audio_server_->CreateTrack( |
| 83 GetProxy(&audio_track_), GetProxy(&media_renderer_)); |
| 80 audio_track_.set_connection_error_handler([this]() { | 84 audio_track_.set_connection_error_handler([this]() { |
| 81 OnConnectionError("audio_track"); | 85 OnConnectionError("audio_track"); |
| 82 }); | 86 }); |
| 87 media_renderer_.set_connection_error_handler([this]() { |
| 88 OnConnectionError("media_renderer"); |
| 89 }); |
| 83 | 90 |
| 84 // Query the sink's format capabilities. | 91 // Query the sink's format capabilities. |
| 85 AudioTrackDescriptorPtr sink_desc; | 92 Array<MediaTypeSetPtr> supported_media_types; |
| 86 auto desc_cbk = [&sink_desc](AudioTrackDescriptorPtr desc) { | 93 auto desc_cbk = [&supported_media_types](Array<MediaTypeSetPtr> desc) { |
| 87 sink_desc = desc.Pass(); | 94 supported_media_types = desc.Pass(); |
| 88 }; | 95 }; |
| 89 audio_track_->Describe(AudioTrack::DescribeCallback(desc_cbk)); | 96 media_renderer_->GetSupportedMediaTypes(desc_cbk); |
| 90 | 97 |
| 91 // TODO(johngro): this pattern is awkward. We really don't want to be | 98 // TODO(johngro): this pattern is awkward. We really don't want to be |
| 92 // calling WaitForIncomingResponse, even if we were able supply a timeout. | 99 // calling WaitForIncomingResponse, even if we were able supply a timeout. |
| 93 // The best practice would be to defer to a handler for the message we are | 100 // The best practice would be to defer to a handler for the message we are |
| 94 // expecting to eventually come back. | 101 // expecting to eventually come back. |
| 95 // | 102 // |
| 96 // But... what if the message never comes back? Perhaps the service is not | 103 // But... what if the message never comes back? Perhaps the service is not |
| 97 // implemented properly, or perhaps the service is malicious. We could | 104 // implemented properly, or perhaps the service is malicious. We could |
| 98 // queue a delayed message on our run loop which indicates a timeout, but | 105 // queue a delayed message on our run loop which indicates a timeout, but |
| 99 // then what happens when when the response to Describe comes back (as | 106 // then what happens when when the response to Describe comes back (as |
| 100 // expected). We don't really have a good way to cancel the "timeout" | 107 // expected). We don't really have a good way to cancel the "timeout" |
| 101 // message once we have queued it. Maintaining all of the bookkeeping | 108 // message once we have queued it. Maintaining all of the bookkeeping |
| 102 // required to nerf the callback when it happens and is discovered to be | 109 // required to nerf the callback when it happens and is discovered to be |
| 103 // useless is going to get very old, very fast. | 110 // useless is going to get very old, very fast. |
| 104 // | 111 // |
| 105 // For now, we just do the evil thing and block during init, but I sure do | 112 // For now, we just do the evil thing and block during init, but I sure do |
| 106 // wish there was something nicer we could do. | 113 // wish there was something nicer we could do. |
| 107 if (!audio_track_.WaitForIncomingResponse()) { | 114 if (!media_renderer_.WaitForIncomingResponse()) { |
| 108 MOJO_LOG(ERROR) | 115 MOJO_LOG(ERROR) |
| 109 << "Failed to fetch sync capabilities; no response received."; | 116 << "Failed to fetch sync capabilities; no response received."; |
| 110 Shutdown(); | 117 Shutdown(); |
| 111 return; | 118 return; |
| 112 } | 119 } |
| 113 | 120 |
| 114 // TODO(johngro): do something useful with our capabilities description. | 121 // TODO(johngro): do something useful with our capabilities description. |
| 115 sink_desc.reset(); | 122 supported_media_types.reset(); |
| 116 | 123 |
| 117 // Grab the timeline consumer interface for our audio renderer. | 124 // Grab the timeline consumer interface for our audio renderer. |
| 118 MediaTimelineControlSitePtr timeline_control_site; | 125 MediaTimelineControlSitePtr timeline_control_site; |
| 119 audio_track_->GetTimelineControlSite(GetProxy(&timeline_control_site)); | 126 media_renderer_->GetTimelineControlSite(GetProxy(&timeline_control_site)); |
| 120 timeline_control_site->GetTimelineConsumer(GetProxy(&timeline_consumer_)); | 127 timeline_control_site->GetTimelineConsumer(GetProxy(&timeline_consumer_)); |
| 121 timeline_consumer_.set_connection_error_handler( | 128 timeline_consumer_.set_connection_error_handler( |
| 122 [this]() { OnConnectionError("timeline_consumer"); }); | 129 [this]() { OnConnectionError("timeline_consumer"); }); |
| 123 | 130 |
| 124 // Configure our sink for 16-bit 48KHz mono. | 131 // Configure our sink for 16-bit 48KHz mono. |
| 125 AudioTrackConfigurationPtr cfg = AudioTrackConfiguration::New(); | |
| 126 | |
| 127 AudioMediaTypeDetailsPtr pcm_cfg = AudioMediaTypeDetails::New(); | 132 AudioMediaTypeDetailsPtr pcm_cfg = AudioMediaTypeDetails::New(); |
| 128 pcm_cfg->sample_format = AudioSampleFormat::SIGNED_16; | 133 pcm_cfg->sample_format = AudioSampleFormat::SIGNED_16; |
| 129 pcm_cfg->channels = 1; | 134 pcm_cfg->channels = 1; |
| 130 pcm_cfg->frames_per_second = SAMP_FREQ; | 135 pcm_cfg->frames_per_second = SAMP_FREQ; |
| 131 | 136 |
| 132 cfg->media_type = MediaType::New(); | 137 MediaTypePtr media_type = MediaType::New(); |
| 133 cfg->media_type->medium = MediaTypeMedium::AUDIO; | 138 media_type->medium = MediaTypeMedium::AUDIO; |
| 134 cfg->media_type->details = MediaTypeDetails::New(); | 139 media_type->details = MediaTypeDetails::New(); |
| 135 cfg->media_type->details->set_audio(pcm_cfg.Pass()); | 140 media_type->details->set_audio(pcm_cfg.Pass()); |
| 136 cfg->media_type->encoding = MediaType::kAudioEncodingLpcm; | 141 media_type->encoding = MediaType::kAudioEncodingLpcm; |
| 137 | 142 |
| 143 media_renderer_->SetMediaType(media_type.Pass()); |
| 138 MediaConsumerPtr pipe; | 144 MediaConsumerPtr pipe; |
| 139 audio_track_->Configure(cfg.Pass(), GetProxy(&pipe)); | 145 media_renderer_->GetConsumer(GetProxy(&pipe)); |
| 140 | 146 |
| 141 // Now that the configuration request is in-flight and we our media pipe | 147 // Now that the configuration request is in-flight and we our media pipe |
| 142 // proxy, pass its interface to our circular buffer helper, set up our | 148 // proxy, pass its interface to our circular buffer helper, set up our |
| 143 // high/low water marks, register our callback, and start to buffer our audio. | 149 // high/low water marks, register our callback, and start to buffer our audio. |
| 144 audio_pipe_.reset(new CircularBufferMediaPipeAdapter(pipe.Pass())); | 150 audio_pipe_.reset(new CircularBufferMediaPipeAdapter(pipe.Pass())); |
| 145 audio_pipe_->Init(USecToBytes(BUF_DEPTH_USEC)); | 151 audio_pipe_->Init(USecToBytes(BUF_DEPTH_USEC)); |
| 146 audio_pipe_->SetSignalCallback( | 152 audio_pipe_->SetSignalCallback( |
| 147 [this](MediaResult res) -> void { | 153 [this](MediaResult res) -> void { |
| 148 GenerateToneCbk(res); | 154 GenerateToneCbk(res); |
| 149 }); | 155 }); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 | 244 |
| 239 } // namespace examples | 245 } // namespace examples |
| 240 } // namespace audio | 246 } // namespace audio |
| 241 } // namespace media | 247 } // namespace media |
| 242 } // namespace mojo | 248 } // namespace mojo |
| 243 | 249 |
| 244 MojoResult MojoMain(MojoHandle app_request) { | 250 MojoResult MojoMain(MojoHandle app_request) { |
| 245 mojo::media::audio::examples::PlayToneApp play_tone_app; | 251 mojo::media::audio::examples::PlayToneApp play_tone_app; |
| 246 return mojo::RunApplication(app_request, &play_tone_app); | 252 return mojo::RunApplication(app_request, &play_tone_app); |
| 247 } | 253 } |
| OLD | NEW |