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; |
44 if (!base::PathExists(base::FilePath(kPostProcessingPipelineFilePath))) { | 37 |
45 LOG(WARNING) << "No post-processing config found in " | 38 StreamPipelineDescriptor::StreamPipelineDescriptor( |
| 39 const StreamPipelineDescriptor& other) |
| 40 : StreamPipelineDescriptor(other.pipeline, other.stream_types) {} |
| 41 |
| 42 PostProcessingPipelineParser::PostProcessingPipelineParser( |
| 43 const std::string& json) { |
| 44 if (json.empty() && |
| 45 !base::PathExists(base::FilePath(kPostProcessingPipelineFilePath))) { |
| 46 LOG(WARNING) << "Could not open post-processing config in " |
46 << kPostProcessingPipelineFilePath << "."; | 47 << kPostProcessingPipelineFilePath << "."; |
47 return; | 48 return; |
48 } | 49 } |
49 | 50 |
50 config_dict_ = base::DictionaryValue::From( | 51 if (json.empty()) { |
51 DeserializeJsonFromFile(base::FilePath(kPostProcessingPipelineFilePath))); | 52 config_dict_ = base::DictionaryValue::From(DeserializeJsonFromFile( |
52 CHECK(config_dict_->GetDictionary("post_processing", &pipeline_dict_)) | 53 base::FilePath(kPostProcessingPipelineFilePath))); |
53 << "No \"post_processing\" object found in " | 54 } else { |
54 << kPostProcessingPipelineFilePath; | 55 config_dict_ = base::DictionaryValue::From(DeserializeFromJson(json)); |
| 56 } |
| 57 |
| 58 CHECK(config_dict_) << "Invalid JSON in " << kPostProcessingPipelineFilePath; |
55 } | 59 } |
56 | 60 |
57 base::ListValue* PostProcessingPipelineParser::GetPipelineByDeviceId( | 61 PostProcessingPipelineParser::~PostProcessingPipelineParser() = default; |
58 const std::string& device_id) { | 62 |
59 if (!pipeline_dict_) { | 63 std::vector<StreamPipelineDescriptor> |
60 return nullptr; | 64 PostProcessingPipelineParser::GetStreamPipelines() { |
| 65 base::ListValue* pipelines_list; |
| 66 std::vector<StreamPipelineDescriptor> descriptors; |
| 67 if (!config_dict_ || |
| 68 !config_dict_->GetList(kOutputStreamsKey, &pipelines_list)) { |
| 69 LOG(WARNING) << "No post-processors found for streams (key = " |
| 70 << kOutputStreamsKey |
| 71 << ").\n No stream-specific processing will occur."; |
| 72 return descriptors; |
61 } | 73 } |
| 74 for (size_t i = 0; i < pipelines_list->GetSize(); ++i) { |
| 75 base::DictionaryValue* pipeline_description_dict; |
| 76 CHECK(pipelines_list->GetDictionary(i, &pipeline_description_dict)); |
62 | 77 |
63 base::ListValue* out_list; | 78 base::ListValue* processors_list; |
64 std::string key = GetPipelineKey(device_id); | 79 CHECK(pipeline_description_dict->GetList(kProcessorsKey, &processors_list)); |
65 if (!pipeline_dict_->GetList(key, &out_list)) { | 80 |
| 81 base::ListValue* streams_list; |
| 82 CHECK(pipeline_description_dict->GetList(kStreamsKey, &streams_list)); |
| 83 std::unordered_set<std::string> streams_set; |
| 84 for (size_t stream = 0; stream < streams_list->GetSize(); ++stream) { |
| 85 std::string stream_name; |
| 86 CHECK(streams_list->GetString(stream, &stream_name)); |
| 87 CHECK(streams_set.insert(stream_name).second) |
| 88 << "Duplicate stream type: " << stream_name; |
| 89 } |
| 90 |
| 91 descriptors.emplace_back(processors_list, std::move(streams_set)); |
| 92 } |
| 93 return descriptors; |
| 94 } |
| 95 |
| 96 std::string PostProcessingPipelineParser::GetFilePath() { |
| 97 return kPostProcessingPipelineFilePath; |
| 98 } |
| 99 |
| 100 base::ListValue* PostProcessingPipelineParser::GetMixPipeline() { |
| 101 return GetPipelineByKey(kMixPipelineKey); |
| 102 } |
| 103 |
| 104 base::ListValue* PostProcessingPipelineParser::GetLinearizePipeline() { |
| 105 return GetPipelineByKey(kLinearizePipelineKey); |
| 106 } |
| 107 |
| 108 base::ListValue* PostProcessingPipelineParser::GetPipelineByKey( |
| 109 const std::string& key) { |
| 110 base::DictionaryValue* stream_dict; |
| 111 if (!config_dict_ || !config_dict_->GetDictionary(key, &stream_dict)) { |
66 LOG(WARNING) << "No post-processor description found for \"" << key | 112 LOG(WARNING) << "No post-processor description found for \"" << key |
67 << "\" in " << kPostProcessingPipelineFilePath | 113 << "\" in " << kPostProcessingPipelineFilePath |
68 << ". Using passthrough."; | 114 << ". Using passthrough."; |
69 return nullptr; | 115 return nullptr; |
70 } | 116 } |
| 117 base::ListValue* out_list; |
| 118 CHECK(stream_dict->GetList(kProcessorsKey, &out_list)); |
| 119 |
71 return out_list; | 120 return out_list; |
72 } | 121 } |
73 | 122 |
74 } // namepsace media | 123 } // namepsace media |
75 } // namespace chromecast | 124 } // namespace chromecast |
OLD | NEW |