| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "chromecast/media/cma/backend/alsa/post_processing_pipeline_parser.h" | 5 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline_parser.h" |
| 6 | 6 |
| 7 #include "base/files/file_path.h" | 7 #include "base/files/file_path.h" |
| 8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "chromecast/base/serializers.h" | 11 #include "chromecast/base/serializers.h" |
| 12 #include "chromecast/media/base/audio_device_ids.h" | 12 #include "chromecast/media/base/audio_device_ids.h" |
| 13 #include "media/audio/audio_device_description.h" | 13 #include "media/audio/audio_device_description.h" |
| 14 | 14 |
| 15 namespace chromecast { | 15 namespace chromecast { |
| 16 namespace media { | 16 namespace media { |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 const base::FilePath::CharType kPostProcessingPipelineFilePath[] = | 20 const base::FilePath::CharType kPostProcessingPipelineFilePath[] = |
| 21 FILE_PATH_LITERAL("/etc/cast_audio.json"); | 21 FILE_PATH_LITERAL("/etc/cast_audio.json"); |
| 22 | 22 |
| 23 const char kMediaPipelineKey[] = "media"; | 23 const char kOutputStreamsKey[] = "output_streams"; |
| 24 const char kTtsPipelineKey[] = "tts"; | 24 const char kMixPipelineKey[] = "mix"; |
| 25 | 25 const char kLinearizePipelineKey[] = "linearize"; |
| 26 // TODO(bshaya): Use AudioContentType instead. | 26 const char kProcessorsKey[] = "processors"; |
| 27 std::string GetPipelineKey(const std::string& device_id) { | 27 const char kStreamsKey[] = "streams"; |
| 28 if (device_id == kTtsAudioDeviceId) { | |
| 29 return kTtsPipelineKey; | |
| 30 } | |
| 31 if (device_id == ::media::AudioDeviceDescription::kDefaultDeviceId) { | |
| 32 return kMediaPipelineKey; | |
| 33 } | |
| 34 NOTREACHED() << "Invalid device_id: " << device_id; | |
| 35 return ""; | |
| 36 } | |
| 37 | 28 |
| 38 } // namespace | 29 } // namespace |
| 39 | 30 |
| 40 PostProcessingPipelineParser::PostProcessingPipelineParser() = default; | 31 StreamPipelineDescriptor::StreamPipelineDescriptor( |
| 41 PostProcessingPipelineParser::~PostProcessingPipelineParser() = default; | 32 base::ListValue* pipeline_in, |
| 33 const std::unordered_set<std::string>& stream_types_in) |
| 34 : pipeline(pipeline_in), stream_types(stream_types_in) {} |
| 42 | 35 |
| 43 void PostProcessingPipelineParser::Initialize() { | 36 StreamPipelineDescriptor::~StreamPipelineDescriptor() = default; |
| 37 |
| 38 StreamPipelineDescriptor::StreamPipelineDescriptor( |
| 39 const StreamPipelineDescriptor& other) |
| 40 : StreamPipelineDescriptor(other.pipeline, other.stream_types) {} |
| 41 |
| 42 PostProcessingPipelineParser::PostProcessingPipelineParser( |
| 43 const std::string& json) { |
| 44 config_dict_ = base::DictionaryValue::From(DeserializeFromJson(json)); |
| 45 } |
| 46 |
| 47 PostProcessingPipelineParser::PostProcessingPipelineParser() { |
| 44 if (!base::PathExists(base::FilePath(kPostProcessingPipelineFilePath))) { | 48 if (!base::PathExists(base::FilePath(kPostProcessingPipelineFilePath))) { |
| 45 LOG(WARNING) << "No post-processing config found in " | 49 LOG(WARNING) << "Could not open post-processing config in " |
| 46 << kPostProcessingPipelineFilePath << "."; | 50 << kPostProcessingPipelineFilePath << "."; |
| 47 return; | 51 return; |
| 48 } | 52 } |
| 49 | 53 |
| 50 config_dict_ = base::DictionaryValue::From( | 54 config_dict_ = base::DictionaryValue::From( |
| 51 DeserializeJsonFromFile(base::FilePath(kPostProcessingPipelineFilePath))); | 55 DeserializeJsonFromFile(base::FilePath(kPostProcessingPipelineFilePath))); |
| 52 CHECK(config_dict_->GetDictionary("post_processing", &pipeline_dict_)) | 56 // TODO(bshaya): Parse and print an ascii visualization of the pipeline. |
| 53 << "No \"post_processing\" object found in " | |
| 54 << kPostProcessingPipelineFilePath; | |
| 55 } | 57 } |
| 56 | 58 |
| 57 base::ListValue* PostProcessingPipelineParser::GetPipelineByDeviceId( | 59 PostProcessingPipelineParser::~PostProcessingPipelineParser() = default; |
| 58 const std::string& device_id) { | 60 |
| 59 if (!pipeline_dict_) { | 61 std::vector<StreamPipelineDescriptor> |
| 60 return nullptr; | 62 PostProcessingPipelineParser::GetStreamPipelines() { |
| 63 base::ListValue* pipelines_list; |
| 64 std::vector<StreamPipelineDescriptor> descriptors; |
| 65 if (!config_dict_ || |
| 66 !config_dict_->GetList(kOutputStreamsKey, &pipelines_list)) { |
| 67 LOG(WARNING) << "No post-processors found for streams (key = " |
| 68 << kOutputStreamsKey |
| 69 << ").\n No stream-specific processing will occur."; |
| 70 return descriptors; |
| 61 } | 71 } |
| 72 for (size_t i = 0; i < pipelines_list->GetSize(); ++i) { |
| 73 base::DictionaryValue* pipeline_description_dict; |
| 74 CHECK(pipelines_list->GetDictionary(i, &pipeline_description_dict)); |
| 62 | 75 |
| 63 base::ListValue* out_list; | 76 base::ListValue* processors_list; |
| 64 std::string key = GetPipelineKey(device_id); | 77 CHECK(pipeline_description_dict->GetList(kProcessorsKey, &processors_list)); |
| 65 if (!pipeline_dict_->GetList(key, &out_list)) { | 78 |
| 79 base::ListValue* streams_list; |
| 80 CHECK(pipeline_description_dict->GetList(kStreamsKey, &streams_list)); |
| 81 std::unordered_set<std::string> streams_set; |
| 82 for (size_t stream = 0; stream < streams_list->GetSize(); ++stream) { |
| 83 std::string stream_name; |
| 84 CHECK(streams_list->GetString(stream, &stream_name)); |
| 85 CHECK(streams_set.insert(stream_name).second) |
| 86 << "Duplicate stream type: " << stream_name; |
| 87 } |
| 88 |
| 89 descriptors.emplace_back(processors_list, std::move(streams_set)); |
| 90 } |
| 91 return descriptors; |
| 92 } |
| 93 |
| 94 std::string PostProcessingPipelineParser::GetFilePath() { |
| 95 return kPostProcessingPipelineFilePath; |
| 96 } |
| 97 |
| 98 base::ListValue* PostProcessingPipelineParser::GetMixPipeline() { |
| 99 return GetPipelineByKey(kMixPipelineKey); |
| 100 } |
| 101 |
| 102 base::ListValue* PostProcessingPipelineParser::GetLinearizePipeline() { |
| 103 return GetPipelineByKey(kLinearizePipelineKey); |
| 104 } |
| 105 |
| 106 base::ListValue* PostProcessingPipelineParser::GetPipelineByKey( |
| 107 const std::string& key) { |
| 108 base::DictionaryValue* stream_dict; |
| 109 if (!config_dict_ || !config_dict_->GetDictionary(key, &stream_dict)) { |
| 66 LOG(WARNING) << "No post-processor description found for \"" << key | 110 LOG(WARNING) << "No post-processor description found for \"" << key |
| 67 << "\" in " << kPostProcessingPipelineFilePath | 111 << "\" in " << kPostProcessingPipelineFilePath |
| 68 << ". Using passthrough."; | 112 << ". Using passthrough."; |
| 69 return nullptr; | 113 return nullptr; |
| 70 } | 114 } |
| 115 base::ListValue* out_list; |
| 116 CHECK(stream_dict->GetList(kProcessorsKey, &out_list)); |
| 117 |
| 71 return out_list; | 118 return out_list; |
| 72 } | 119 } |
| 73 | 120 |
| 74 } // namepsace media | 121 } // namepsace media |
| 75 } // namespace chromecast | 122 } // namespace chromecast |
| OLD | NEW |