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::file_path() { |
| 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 |