Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: media/base/android/media_source_player_unittest.cc

Issue 1008093002: Determine the audible state in MediaSourcePlayer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Minor fixes Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/android/media_source_player.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 <string> 5 #include <string>
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
(...skipping 28 matching lines...) Expand all
39 // fix flaky pointer-based MDJ inequality testing. See http://crbug.com/327839. 39 // fix flaky pointer-based MDJ inequality testing. See http://crbug.com/327839.
40 40
41 // Mock of MediaPlayerManager for testing purpose. 41 // Mock of MediaPlayerManager for testing purpose.
42 class MockMediaPlayerManager : public MediaPlayerManager { 42 class MockMediaPlayerManager : public MediaPlayerManager {
43 public: 43 public:
44 explicit MockMediaPlayerManager(base::MessageLoop* message_loop) 44 explicit MockMediaPlayerManager(base::MessageLoop* message_loop)
45 : message_loop_(message_loop), 45 : message_loop_(message_loop),
46 playback_completed_(false), 46 playback_completed_(false),
47 num_resources_requested_(0), 47 num_resources_requested_(0),
48 num_metadata_changes_(0), 48 num_metadata_changes_(0),
49 timestamp_updated_(false) {} 49 timestamp_updated_(false),
50 is_audible_(false),
51 is_delay_expired_(false) {}
50 ~MockMediaPlayerManager() override {} 52 ~MockMediaPlayerManager() override {}
51 53
52 // MediaPlayerManager implementation. 54 // MediaPlayerManager implementation.
53 MediaResourceGetter* GetMediaResourceGetter() override { return NULL; } 55 MediaResourceGetter* GetMediaResourceGetter() override { return NULL; }
54 MediaUrlInterceptor* GetMediaUrlInterceptor() override { return NULL; } 56 MediaUrlInterceptor* GetMediaUrlInterceptor() override { return NULL; }
55 void OnTimeUpdate(int player_id, 57 void OnTimeUpdate(int player_id,
56 base::TimeDelta current_time, 58 base::TimeDelta current_time,
57 base::TimeTicks current_time_ticks) override { 59 base::TimeTicks current_time_ticks) override {
58 timestamp_updated_ = true; 60 timestamp_updated_ = true;
59 } 61 }
60 void OnMediaMetadataChanged(int player_id, 62 void OnMediaMetadataChanged(int player_id,
61 base::TimeDelta duration, 63 base::TimeDelta duration,
62 int width, 64 int width,
63 int height, 65 int height,
64 bool success) override { 66 bool success) override {
65 num_metadata_changes_++; 67 num_metadata_changes_++;
66 } 68 }
67 void OnPlaybackComplete(int player_id) override { 69 void OnPlaybackComplete(int player_id) override {
68 playback_completed_ = true; 70 playback_completed_ = true;
69 if (message_loop_->is_running()) 71 if (message_loop_->is_running())
70 message_loop_->Quit(); 72 message_loop_->Quit();
71 } 73 }
72 void OnMediaInterrupted(int player_id) override {} 74 void OnMediaInterrupted(int player_id) override {}
73 void OnBufferingUpdate(int player_id, int percentage) override {} 75 void OnBufferingUpdate(int player_id, int percentage) override {}
74 void OnSeekComplete(int player_id, 76 void OnSeekComplete(int player_id,
75 const base::TimeDelta& current_time) override {} 77 const base::TimeDelta& current_time) override {}
76 void OnError(int player_id, int error) override {} 78 void OnError(int player_id, int error) override {}
77 void OnVideoSizeChanged(int player_id, int width, int height) override {} 79 void OnVideoSizeChanged(int player_id, int width, int height) override {}
78 void OnAudibleStateChanged(int player_id, bool is_audible_now) override {}
79 void OnWaitingForDecryptionKey(int player_id) override {} 80 void OnWaitingForDecryptionKey(int player_id) override {}
80 MediaPlayerAndroid* GetFullscreenPlayer() override { return NULL; } 81 MediaPlayerAndroid* GetFullscreenPlayer() override { return NULL; }
81 MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; } 82 MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; }
82 void RequestFullScreen(int player_id) override {} 83 void RequestFullScreen(int player_id) override {}
83 #if defined(VIDEO_HOLE) 84 #if defined(VIDEO_HOLE)
84 bool ShouldUseVideoOverlayForEmbeddedEncryptedVideo() override { 85 bool ShouldUseVideoOverlayForEmbeddedEncryptedVideo() override {
85 return false; 86 return false;
86 } 87 }
87 #endif // defined(VIDEO_HOLE) 88 #endif // defined(VIDEO_HOLE)
88 89
90 void OnAudibleStateChanged(int player_id, bool is_audible_now) override {
91 is_audible_ = is_audible_now;
92 }
93
89 bool playback_completed() const { 94 bool playback_completed() const {
90 return playback_completed_; 95 return playback_completed_;
91 } 96 }
92 97
93 int num_resources_requested() const { 98 int num_resources_requested() const {
94 return num_resources_requested_; 99 return num_resources_requested_;
95 } 100 }
96 101
97 int num_metadata_changes() const { 102 int num_metadata_changes() const {
98 return num_metadata_changes_; 103 return num_metadata_changes_;
99 } 104 }
100 105
101 void OnMediaResourcesRequested(int player_id) { 106 void OnMediaResourcesRequested(int player_id) {
102 num_resources_requested_++; 107 num_resources_requested_++;
103 } 108 }
104 109
105 bool timestamp_updated() const { 110 bool timestamp_updated() const {
106 return timestamp_updated_; 111 return timestamp_updated_;
107 } 112 }
108 113
109 void ResetTimestampUpdated() { 114 void ResetTimestampUpdated() {
110 timestamp_updated_ = false; 115 timestamp_updated_ = false;
111 } 116 }
112 117
118 bool is_audible() const {
119 return is_audible_;
120 }
121
122 bool is_delay_expired() const {
123 return is_delay_expired_;
124 }
125
126 void SetDelayExpired(bool value) {
127 is_delay_expired_ = value;
128 }
129
113 private: 130 private:
114 base::MessageLoop* message_loop_; 131 base::MessageLoop* message_loop_;
115 bool playback_completed_; 132 bool playback_completed_;
116 // The number of resource requests this object has seen. 133 // The number of resource requests this object has seen.
117 int num_resources_requested_; 134 int num_resources_requested_;
118 // The number of metadata changes reported by the player. 135 // The number of metadata changes reported by the player.
119 int num_metadata_changes_; 136 int num_metadata_changes_;
120 // Playback timestamp was updated. 137 // Playback timestamp was updated.
121 bool timestamp_updated_; 138 bool timestamp_updated_;
139 // Audible state of the pipeline
140 bool is_audible_;
141 // Helper flag to ensure delay for WaitForDelay().
142 bool is_delay_expired_;
122 143
123 DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager); 144 DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager);
124 }; 145 };
125 146
126 class MockDemuxerAndroid : public DemuxerAndroid { 147 class MockDemuxerAndroid : public DemuxerAndroid {
127 public: 148 public:
128 explicit MockDemuxerAndroid(base::MessageLoop* message_loop) 149 explicit MockDemuxerAndroid(base::MessageLoop* message_loop)
129 : message_loop_(message_loop), 150 : message_loop_(message_loop),
130 num_data_requests_(0), 151 num_data_requests_(0),
131 num_seek_requests_(0), 152 num_seek_requests_(0),
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 MediaSourcePlayerTest() 190 MediaSourcePlayerTest()
170 : manager_(&message_loop_), 191 : manager_(&message_loop_),
171 demuxer_(new MockDemuxerAndroid(&message_loop_)), 192 demuxer_(new MockDemuxerAndroid(&message_loop_)),
172 player_(0, &manager_, 193 player_(0, &manager_,
173 base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested, 194 base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested,
174 base::Unretained(&manager_)), 195 base::Unretained(&manager_)),
175 scoped_ptr<DemuxerAndroid>(demuxer_), 196 scoped_ptr<DemuxerAndroid>(demuxer_),
176 GURL()), 197 GURL()),
177 decoder_callback_hook_executed_(false), 198 decoder_callback_hook_executed_(false),
178 surface_texture_a_is_next_(true) {} 199 surface_texture_a_is_next_(true) {}
200
179 ~MediaSourcePlayerTest() override {} 201 ~MediaSourcePlayerTest() override {}
180 202
181 protected: 203 protected:
182 // Get the decoder job from the MediaSourcePlayer. The return value must not 204 // Get the decoder job from the MediaSourcePlayer. The return value must not
183 // be NULL. 205 // be NULL.
184 MediaDecoderJob* GetMediaDecoderJob(bool is_audio) { 206 MediaDecoderJob* GetMediaDecoderJob(bool is_audio) {
185 if (is_audio) { 207 if (is_audio) {
186 return reinterpret_cast<MediaDecoderJob*>( 208 return reinterpret_cast<MediaDecoderJob*>(
187 player_.audio_decoder_job_.get()); 209 player_.audio_decoder_job_.get());
188 } 210 }
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 EXPECT_TRUE(GetMediaDecoderJob(is_audio)->is_decoding()); 554 EXPECT_TRUE(GetMediaDecoderJob(is_audio)->is_decoding());
533 EXPECT_TRUE(GetMediaCodecBridge(is_audio)); 555 EXPECT_TRUE(GetMediaCodecBridge(is_audio));
534 EXPECT_TRUE(!is_clock_manager || 556 EXPECT_TRUE(!is_clock_manager ||
535 target_timestamp == player_.GetCurrentTime()); 557 target_timestamp == player_.GetCurrentTime());
536 current_timestamp += 30; 558 current_timestamp += 30;
537 WaitForDecodeDone(is_audio, !is_audio); 559 WaitForDecodeDone(is_audio, !is_audio);
538 } 560 }
539 EXPECT_LE(target_timestamp, player_.GetCurrentTime()); 561 EXPECT_LE(target_timestamp, player_.GetCurrentTime());
540 } 562 }
541 563
564 void PlayAudioForTimeInterval(const base::TimeDelta& start_timestamp,
565 const base::TimeDelta& target_timestamp ) {
566
567 DemuxerData data = CreateReadFromDemuxerAckForAudio(1);
568 int current_timestamp = start_timestamp.InMilliseconds();
569 int stop_timestamp = target_timestamp.InMilliseconds();
570 while (current_timestamp < stop_timestamp) {
571 data.access_units[0].timestamp =
572 base::TimeDelta::FromMilliseconds(current_timestamp);
573 player_.OnDemuxerDataAvailable(data);
574 current_timestamp += 30;
575 WaitForAudioDecodeDone();
576 }
577 }
578
579 void WaitForDelay(const base::TimeDelta& delay) {
580 // Let the message_loop_ process events.
581 // We post delayed task and RunUnitilIdle() until it signals.
582
583 manager_.SetDelayExpired(false);
584 message_loop_.PostDelayedTask(
585 FROM_HERE,
586 base::Bind(&MockMediaPlayerManager::SetDelayExpired,
587 base::Unretained(&manager_),
588 true),
589 delay);
590
591 while (!manager_.is_delay_expired())
592 message_loop_.RunUntilIdle();
593 }
594
542 DemuxerData CreateReadFromDemuxerAckWithConfigChanged( 595 DemuxerData CreateReadFromDemuxerAckWithConfigChanged(
543 bool is_audio, 596 bool is_audio,
544 int config_unit_index, 597 int config_unit_index,
545 const DemuxerConfigs& configs) { 598 const DemuxerConfigs& configs) {
546 DemuxerData data; 599 DemuxerData data;
547 data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO; 600 data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
548 data.access_units.resize(config_unit_index + 1); 601 data.access_units.resize(config_unit_index + 1);
549 602
550 for (int i = 0; i < config_unit_index; ++i) 603 for (int i = 0; i < config_unit_index; ++i)
551 data.access_units[i] = CreateAccessUnitWithData(is_audio, i, false); 604 data.access_units[i] = CreateAccessUnitWithData(is_audio, i, false);
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 } 888 }
836 889
837 bool IsRequestingDemuxerData(bool is_audio) { 890 bool IsRequestingDemuxerData(bool is_audio) {
838 return GetMediaDecoderJob(is_audio)->is_requesting_demuxer_data_; 891 return GetMediaDecoderJob(is_audio)->is_requesting_demuxer_data_;
839 } 892 }
840 893
841 bool IsDrainingDecoder(bool is_audio) { 894 bool IsDrainingDecoder(bool is_audio) {
842 return GetMediaDecoderJob(is_audio)->drain_decoder_; 895 return GetMediaDecoderJob(is_audio)->drain_decoder_;
843 } 896 }
844 897
898 protected:
845 base::MessageLoop message_loop_; 899 base::MessageLoop message_loop_;
846 MockMediaPlayerManager manager_; 900 MockMediaPlayerManager manager_;
847 MockDemuxerAndroid* demuxer_; // Owned by |player_|. 901 MockDemuxerAndroid* demuxer_; // Owned by |player_|.
848 MediaSourcePlayer player_; 902 MediaSourcePlayer player_;
849 903
850 // Track whether a possibly async decoder callback test hook has run. 904 // Track whether a possibly async decoder callback test hook has run.
851 bool decoder_callback_hook_executed_; 905 bool decoder_callback_hook_executed_;
852 906
853 // We need to keep the surface texture while the decoder is actively decoding. 907 // We need to keep the surface texture while the decoder is actively decoding.
854 // Otherwise, it may trigger unexpected crashes on some devices. To switch 908 // Otherwise, it may trigger unexpected crashes on some devices. To switch
855 // surfaces, tests need to create a new surface texture without releasing 909 // surfaces, tests need to create a new surface texture without releasing
856 // their previous one. In CreateNextTextureAndSetVideoSurface(), we toggle 910 // their previous one. In CreateNextTextureAndSetVideoSurface(), we toggle
857 // between two surface textures, only replacing the N-2 texture. Assumption is 911 // between two surface textures, only replacing the N-2 texture. Assumption is
858 // that no more than N-1 texture is in use by decoder when 912 // that no more than N-1 texture is in use by decoder when
859 // CreateNextTextureAndSetVideoSurface() is called. 913 // CreateNextTextureAndSetVideoSurface() is called.
860 scoped_refptr<gfx::SurfaceTexture> surface_texture_a_; 914 scoped_refptr<gfx::SurfaceTexture> surface_texture_a_;
861 scoped_refptr<gfx::SurfaceTexture> surface_texture_b_; 915 scoped_refptr<gfx::SurfaceTexture> surface_texture_b_;
862 bool surface_texture_a_is_next_; 916 bool surface_texture_a_is_next_;
863 int next_texture_id_; 917 int next_texture_id_;
864 918
919 bool verify_not_audible_is_called_;
920
865 DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayerTest); 921 DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayerTest);
866 }; 922 };
867 923
868 TEST_F(MediaSourcePlayerTest, StartAudioDecoderWithValidConfig) { 924 TEST_F(MediaSourcePlayerTest, StartAudioDecoderWithValidConfig) {
869 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); 925 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
870 926
871 // Test audio codec will be created when valid configs and data are passed to 927 // Test audio codec will be created when valid configs and data are passed to
872 // the audio decoder job. 928 // the audio decoder job.
873 StartAudioDecoderJob(); 929 StartAudioDecoderJob();
874 EXPECT_EQ(0, demuxer_->num_seek_requests()); 930 EXPECT_EQ(0, demuxer_->num_seek_requests());
(...skipping 11 matching lines...) Expand all
886 uint8 invalid_codec_data[] = { 0x00, 0xff, 0xff, 0xff, 0xff }; 942 uint8 invalid_codec_data[] = { 0x00, 0xff, 0xff, 0xff, 0xff };
887 configs.audio_extra_data.insert(configs.audio_extra_data.begin(), 943 configs.audio_extra_data.insert(configs.audio_extra_data.begin(),
888 invalid_codec_data, invalid_codec_data + 4); 944 invalid_codec_data, invalid_codec_data + 4);
889 Start(configs); 945 Start(configs);
890 946
891 // Decoder is not created after data is received. 947 // Decoder is not created after data is received.
892 player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0)); 948 player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
893 EXPECT_FALSE(GetMediaCodecBridge(true)); 949 EXPECT_FALSE(GetMediaCodecBridge(true));
894 } 950 }
895 951
952 // timav
953 TEST_F(MediaSourcePlayerTest, AudioDecoderSetsAudibleState) {
954 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
955
956 // No data arrived yet
957 EXPECT_FALSE(manager_.is_audible());
958
959 // Initialize decoder
960 StartAudioDecoderJob();
961 player_.SetVolume(1.0);
962
963 // Process frames until prerolling is done.
964 SeekPlayerWithAbort(true, base::TimeDelta::FromMilliseconds(100));
965 EXPECT_TRUE(IsPrerolling(true));
966 PrerollDecoderToTime(
967 true, base::TimeDelta(), base::TimeDelta::FromMilliseconds(100), false);
968 EXPECT_TRUE(IsPrerolling(false));
969
970 // Send more packets
971 PlayAudioForTimeInterval(base::TimeDelta::FromMilliseconds(150),
972 base::TimeDelta::FromMilliseconds(220));
973
974 // The player should trigger audible status
975 EXPECT_TRUE(manager_.is_audible());
976
977 // The player release should report a non-audible state.
978 ReleasePlayer();
979 EXPECT_FALSE(manager_.is_audible());
980 }
981
982 TEST_F(MediaSourcePlayerTest, AudioDecoderRemovesAudibleStateWhenPaused) {
983 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
984
985 // No data arrived yet
986 EXPECT_FALSE(manager_.is_audible());
987
988 // Initialize decoder
989 StartAudioDecoderJob();
990 player_.SetVolume(1.0);
991
992 // Process frames until prerolling is done.
993 SeekPlayerWithAbort(true, base::TimeDelta::FromMilliseconds(100));
994 EXPECT_TRUE(IsPrerolling(true));
995 PrerollDecoderToTime(
996 true, base::TimeDelta(), base::TimeDelta::FromMilliseconds(100), false);
997 EXPECT_TRUE(IsPrerolling(false));
998
999 // Send more packets
1000 PlayAudioForTimeInterval(base::TimeDelta::FromMilliseconds(150),
1001 base::TimeDelta::FromMilliseconds(220));
1002
1003 // The player should trigger audible status
1004 EXPECT_TRUE(manager_.is_audible());
1005
1006 // Pause the player
1007 player_.Pause(true);
1008
1009 // Send more packets
1010 PlayAudioForTimeInterval(base::TimeDelta::FromMilliseconds(240),
1011 base::TimeDelta::FromMilliseconds(280));
1012
1013 // The player should trigger audible status again
1014 EXPECT_FALSE(manager_.is_audible());
1015
1016 player_.Release();
1017 }
1018
1019 TEST_F(MediaSourcePlayerTest, AudioDecoderRemovesAudibleStateWhenIdle) {
1020 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
1021
1022 // No data arrived yet
1023 EXPECT_FALSE(manager_.is_audible());
1024
1025 // Initialize decoder
1026 StartAudioDecoderJob();
1027 player_.SetVolume(1.0);
1028
1029 // Process frames until prerolling is done.
1030 SeekPlayerWithAbort(true, base::TimeDelta::FromMilliseconds(100));
1031 EXPECT_TRUE(IsPrerolling(true));
1032 PrerollDecoderToTime(
1033 true, base::TimeDelta(), base::TimeDelta::FromMilliseconds(100), false);
1034 EXPECT_TRUE(IsPrerolling(false));
1035
1036 // Send more packets
1037 PlayAudioForTimeInterval(base::TimeDelta::FromMilliseconds(150),
1038 base::TimeDelta::FromMilliseconds(220));
1039
1040 // The player should trigger audible status
1041 EXPECT_TRUE(manager_.is_audible());
1042
1043 // Simulate the freeze on demuxer: wait for 300 ms
1044 WaitForDelay(base::TimeDelta::FromMilliseconds(300));
1045
1046 // By this time the player should have reported
1047 // that there is no audio.
1048 EXPECT_FALSE(manager_.is_audible());
1049
1050 ReleasePlayer();
1051 }
1052
896 TEST_F(MediaSourcePlayerTest, StartVideoCodecWithValidSurface) { 1053 TEST_F(MediaSourcePlayerTest, StartVideoCodecWithValidSurface) {
897 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); 1054 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
898 1055
899 // Test video codec will not be created until data is received. 1056 // Test video codec will not be created until data is received.
900 StartVideoDecoderJob(); 1057 StartVideoDecoderJob();
901 1058
902 // Set both an initial and a later video surface without receiving any 1059 // Set both an initial and a later video surface without receiving any
903 // demuxed data yet. 1060 // demuxed data yet.
904 CreateNextTextureAndSetVideoSurface(); 1061 CreateNextTextureAndSetVideoSurface();
905 EXPECT_FALSE(GetMediaCodecBridge(false)); 1062 EXPECT_FALSE(GetMediaCodecBridge(false));
(...skipping 1449 matching lines...) Expand 10 before | Expand all | Expand 10 after
2355 // Wait for the metadata change. 2512 // Wait for the metadata change.
2356 while(manager_.num_metadata_changes() == 1) { 2513 while(manager_.num_metadata_changes() == 1) {
2357 player_.OnDemuxerDataAvailable(data); 2514 player_.OnDemuxerDataAvailable(data);
2358 WaitForVideoDecodeDone(); 2515 WaitForVideoDecodeDone();
2359 } 2516 }
2360 EXPECT_EQ(2, manager_.num_metadata_changes()); 2517 EXPECT_EQ(2, manager_.num_metadata_changes());
2361 WaitForVideoDecodeDone(); 2518 WaitForVideoDecodeDone();
2362 } 2519 }
2363 2520
2364 } // namespace media 2521 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_source_player.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698