1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // Tests PPB_MediaStreamAudioTrack interface. 6 7 #include "ppapi/tests/test_media_stream_audio_track.h" 8 9 #include "ppapi/c/private/ppb_testing_private.h" 10 #include "ppapi/cpp/audio_buffer.h" 11 #include "ppapi/cpp/completion_callback.h" 12 #include "ppapi/cpp/instance.h" 13 #include "ppapi/cpp/var.h" 14 #include "ppapi/tests/test_utils.h" 15 #include "ppapi/tests/testing_instance.h" 16 17 REGISTER_TEST_CASE(MediaStreamAudioTrack); 18 19 namespace { 20 21 // Real max defined in 22 // content/renderer/pepper/pepper_media_stream_audio_track_host.cc. 23 const int32_t kMaxNumberOfBuffers = 1000; 24 const int32_t kTimes = 3; 25 const char kJSCode[] = 26 "function gotStream(stream) {" 27 " test_stream = stream;" 28 " var track = stream.getAudioTracks()[0];" 29 " var plugin = document.getElementById('plugin');" 30 " plugin.postMessage(track);" 31 "}" 32 "var constraints = {" 33 " audio: true," 34 " video: false," 35 "};" 36 "navigator.getUserMedia = " 37 " navigator.getUserMedia || navigator.webkitGetUserMedia;" 38 "navigator.getUserMedia(constraints," 39 " gotStream, function() {});"; 40 41 // Helper to check if the |sample_rate| is listed in PP_AudioBuffer_SampleRate 42 // enum. 43 bool IsSampleRateValid(PP_AudioBuffer_SampleRate sample_rate) { 44 switch (sample_rate) { 45 case PP_AUDIOBUFFER_SAMPLERATE_8000: 46 case PP_AUDIOBUFFER_SAMPLERATE_16000: 47 case PP_AUDIOBUFFER_SAMPLERATE_22050: 48 case PP_AUDIOBUFFER_SAMPLERATE_32000: 49 case PP_AUDIOBUFFER_SAMPLERATE_44100: 50 case PP_AUDIOBUFFER_SAMPLERATE_48000: 51 case PP_AUDIOBUFFER_SAMPLERATE_96000: 52 case PP_AUDIOBUFFER_SAMPLERATE_192000: 53 return true; 54 default: 55 return false; 56 } 57 } 58 59 } // namespace 60 61 TestMediaStreamAudioTrack::TestMediaStreamAudioTrack(TestingInstance* instance) 62 : TestCase(instance), 63 event_(instance_->pp_instance()) { 64 } 65 66 bool TestMediaStreamAudioTrack::Init() { 67 return true; 68 } 69 70 TestMediaStreamAudioTrack::~TestMediaStreamAudioTrack() { 71 } 72 73 void TestMediaStreamAudioTrack::RunTests(const std::string& filter) { 74 RUN_TEST(Create, filter); 75 RUN_TEST(GetBuffer, filter); 76 RUN_TEST(Configure, filter); 77 } 78 79 void TestMediaStreamAudioTrack::HandleMessage(const pp::Var& message) { 80 if (message.is_resource()) { 81 audio_track_ = pp::MediaStreamAudioTrack(message.AsResource()); 82 } 83 event_.Signal(); 84 } 85 86 std::string TestMediaStreamAudioTrack::TestCreate() { 87 // Create a track. 88 instance_->EvalScript(kJSCode); 89 event_.Wait(); 90 event_.Reset(); 91 92 ASSERT_FALSE(audio_track_.is_null()); 93 ASSERT_FALSE(audio_track_.HasEnded()); 94 ASSERT_FALSE(audio_track_.GetId().empty()); 95 96 // Close the track. 97 audio_track_.Close(); 98 ASSERT_TRUE(audio_track_.HasEnded()); 99 audio_track_ = pp::MediaStreamAudioTrack(); 100 PASS(); 101 } 102 103 std::string TestMediaStreamAudioTrack::TestGetBuffer() { 104 // Create a track. 105 instance_->EvalScript(kJSCode); 106 event_.Wait(); 107 event_.Reset(); 108 109 ASSERT_FALSE(audio_track_.is_null()); 110 ASSERT_FALSE(audio_track_.HasEnded()); 111 ASSERT_FALSE(audio_track_.GetId().empty()); 112 113 PP_TimeDelta timestamp = 0.0; 114 115 // Get |kTimes| buffers. 116 for (int i = 0; i < kTimes; ++i) { 117 TestCompletionCallbackWithOutput<pp::AudioBuffer> cc( 118 instance_->pp_instance(), false); 119 cc.WaitForResult(audio_track_.GetBuffer(cc.GetCallback())); 120 ASSERT_EQ(PP_OK, cc.result()); 121 pp::AudioBuffer buffer = cc.output(); 122 ASSERT_FALSE(buffer.is_null()); 123 ASSERT_TRUE(IsSampleRateValid(buffer.GetSampleRate())); 124 ASSERT_EQ(buffer.GetSampleSize(), PP_AUDIOBUFFER_SAMPLESIZE_16_BITS); 125 126 ASSERT_GE(buffer.GetTimestamp(), timestamp); 127 timestamp = buffer.GetTimestamp(); 128 129 ASSERT_GT(buffer.GetDataBufferSize(), 0U); 130 ASSERT_TRUE(buffer.GetDataBuffer() != NULL); 131 132 audio_track_.RecycleBuffer(buffer); 133 134 // A recycled buffer should be invalidated. 135 ASSERT_EQ(buffer.GetSampleRate(), PP_AUDIOBUFFER_SAMPLERATE_UNKNOWN); 136 ASSERT_EQ(buffer.GetSampleSize(), PP_AUDIOBUFFER_SAMPLESIZE_UNKNOWN); 137 ASSERT_EQ(buffer.GetDataBufferSize(), 0U); 138 ASSERT_TRUE(buffer.GetDataBuffer() == NULL); 139 } 140 141 // Close the track. 142 audio_track_.Close(); 143 ASSERT_TRUE(audio_track_.HasEnded()); 144 audio_track_ = pp::MediaStreamAudioTrack(); 145 PASS(); 146 } 147 148 std::string TestMediaStreamAudioTrack::TestConfigure() { 149 // Create a track. 150 instance_->EvalScript(kJSCode); 151 event_.Wait(); 152 event_.Reset(); 153 154 ASSERT_FALSE(audio_track_.is_null()); 155 ASSERT_FALSE(audio_track_.HasEnded()); 156 ASSERT_FALSE(audio_track_.GetId().empty()); 157 158 PP_TimeDelta timestamp = 0.0; 159 160 // Configure number of buffers. 161 struct { 162 int32_t buffers; 163 int32_t expect_result; 164 } buffers[] = { 165 { 8, PP_OK }, 166 { 100, PP_OK }, 167 { kMaxNumberOfBuffers, PP_OK }, 168 { -1, PP_ERROR_BADARGUMENT }, 169 { kMaxNumberOfBuffers + 1, PP_OK }, // Clipped to max value. 170 { 0, PP_OK }, // Use default. 171 }; 172 for (size_t i = 0; i < sizeof(buffers) / sizeof(buffers[0]); ++i) { 173 TestCompletionCallback cc_configure(instance_->pp_instance(), false); 174 int32_t attrib_list[] = { 175 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_BUFFERS, buffers[i].buffers, 176 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE, 177 }; 178 cc_configure.WaitForResult( 179 audio_track_.Configure(attrib_list, cc_configure.GetCallback())); 180 ASSERT_EQ(buffers[i].expect_result, cc_configure.result()); 181 182 // Get some buffers. This should also succeed when configure fails. 183 for (int j = 0; j < kTimes; ++j) { 184 TestCompletionCallbackWithOutput<pp::AudioBuffer> cc_get_buffer( 185 instance_->pp_instance(), false); 186 cc_get_buffer.WaitForResult( 187 audio_track_.GetBuffer(cc_get_buffer.GetCallback())); 188 ASSERT_EQ(PP_OK, cc_get_buffer.result()); 189 pp::AudioBuffer buffer = cc_get_buffer.output(); 190 ASSERT_FALSE(buffer.is_null()); 191 ASSERT_TRUE(IsSampleRateValid(buffer.GetSampleRate())); 192 ASSERT_EQ(buffer.GetSampleSize(), PP_AUDIOBUFFER_SAMPLESIZE_16_BITS); 193 194 ASSERT_GE(buffer.GetTimestamp(), timestamp); 195 timestamp = buffer.GetTimestamp(); 196 197 ASSERT_GT(buffer.GetDataBufferSize(), 0U); 198 ASSERT_TRUE(buffer.GetDataBuffer() != NULL); 199 200 audio_track_.RecycleBuffer(buffer); 201 } 202 } 203 204 // Configure should fail while plugin holds buffers. 205 { 206 TestCompletionCallbackWithOutput<pp::AudioBuffer> cc_get_buffer( 207 instance_->pp_instance(), false); 208 cc_get_buffer.WaitForResult( 209 audio_track_.GetBuffer(cc_get_buffer.GetCallback())); 210 ASSERT_EQ(PP_OK, cc_get_buffer.result()); 211 pp::AudioBuffer buffer = cc_get_buffer.output(); 212 int32_t attrib_list[] = { 213 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_BUFFERS, 0, 214 PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE, 215 }; 216 TestCompletionCallback cc_configure(instance_->pp_instance(), false); 217 cc_configure.WaitForResult( 218 audio_track_.Configure(attrib_list, cc_configure.GetCallback())); 219 ASSERT_EQ(PP_ERROR_INPROGRESS, cc_configure.result()); 220 audio_track_.RecycleBuffer(buffer); 221 } 222 223 // Close the track. 224 audio_track_.Close(); 225 ASSERT_TRUE(audio_track_.HasEnded()); 226 audio_track_ = pp::MediaStreamAudioTrack(); 227 PASS(); 228 } 229