Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "remoting/client/plugin/pepper_audio_player.h" | 5 #include "remoting/client/plugin/pepper_audio_player.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 | 10 |
| 11 namespace { | 11 namespace { |
| 12 // Constants used to create an audio configuration resource. | 12 |
| 13 // The sample count we will request from the browser. | 13 // The frame size we will request from the browser. |
| 14 const uint32_t kSampleFrameCount = 4096u; | 14 const int kFrameSizeMs = 40; |
| 15 | |
| 15 // The number of channels in the audio stream (only supporting stereo audio | 16 // The number of channels in the audio stream (only supporting stereo audio |
| 16 // for now). | 17 // for now). |
| 17 const uint32_t kChannels = 2u; | 18 const int kChannels = 2u; |
| 18 const int kSampleSizeBytes = 2; | 19 const int kSampleSizeBytes = 2; |
| 19 | 20 |
| 21 // If queue grows bigger than 150ms we start dropping packets. | |
| 22 const int kMaxQueueLatencyMs = 150; | |
| 23 | |
| 20 PP_AudioSampleRate ConvertToPepperSampleRate( | 24 PP_AudioSampleRate ConvertToPepperSampleRate( |
| 21 remoting::AudioPacket::SamplingRate sampling_rate) { | 25 remoting::AudioPacket::SamplingRate sampling_rate) { |
| 22 switch (sampling_rate) { | 26 switch (sampling_rate) { |
| 23 case remoting::AudioPacket::SAMPLING_RATE_44100: | 27 case remoting::AudioPacket::SAMPLING_RATE_44100: |
| 24 return PP_AUDIOSAMPLERATE_44100; | 28 return PP_AUDIOSAMPLERATE_44100; |
| 25 case remoting::AudioPacket::SAMPLING_RATE_48000: | 29 case remoting::AudioPacket::SAMPLING_RATE_48000: |
| 26 return PP_AUDIOSAMPLERATE_48000; | 30 return PP_AUDIOSAMPLERATE_48000; |
| 27 default: | 31 default: |
| 28 NOTREACHED(); | 32 NOTREACHED(); |
| 29 } | 33 } |
| 30 return PP_AUDIOSAMPLERATE_NONE; | 34 return PP_AUDIOSAMPLERATE_NONE; |
| 31 } | 35 } |
| 32 | 36 |
| 33 } // namespace | 37 } // namespace |
| 34 | 38 |
| 35 namespace remoting { | 39 namespace remoting { |
| 36 | 40 |
| 37 PepperAudioPlayer::PepperAudioPlayer(pp::Instance* instance) | 41 PepperAudioPlayer::PepperAudioPlayer(pp::Instance* instance) |
| 38 : instance_(instance), | 42 : instance_(instance), |
| 39 sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), | 43 sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), |
| 40 samples_per_frame_(kSampleFrameCount), | 44 samples_per_frame_(0), |
| 41 bytes_consumed_(0), | 45 start_failed_(false), |
| 42 start_failed_(false) { | 46 queued_samples_(0), |
| 47 bytes_consumed_(0) { | |
| 43 } | 48 } |
| 44 | 49 |
| 45 PepperAudioPlayer::~PepperAudioPlayer() {} | 50 PepperAudioPlayer::~PepperAudioPlayer() {} |
| 46 | 51 |
| 47 bool PepperAudioPlayer::ResetAudioPlayer( | 52 bool PepperAudioPlayer::ResetAudioPlayer( |
| 48 AudioPacket::SamplingRate sampling_rate) { | 53 AudioPacket::SamplingRate sampling_rate) { |
| 49 sampling_rate_ = sampling_rate; | 54 sampling_rate_ = sampling_rate; |
| 50 PP_AudioSampleRate sample_rate = | 55 PP_AudioSampleRate sample_rate = |
| 51 ConvertToPepperSampleRate(sampling_rate); | 56 ConvertToPepperSampleRate(sampling_rate); |
| 52 | 57 |
| 53 // Ask the browser/device for an appropriate sample frame count size. | 58 // Ask the browser/device for an appropriate frame size. |
| 54 samples_per_frame_ = | 59 samples_per_frame_ = pp::AudioConfig::RecommendSampleFrameCount( |
| 55 pp::AudioConfig::RecommendSampleFrameCount(instance_, | 60 instance_, sample_rate, |
| 56 sample_rate, | 61 kFrameSizeMs * sampling_rate / base::Time::kMillisecondsPerSecond); |
|
Wez
2012/09/12 20:47:57
nit: Since you do a similar calculation based on t
Sergey Ulanov
2012/09/12 21:43:34
Done. Called the new function MsecToSamples()
| |
| 57 kSampleFrameCount); | |
| 58 | 62 |
| 59 // Create an audio configuration resource. | 63 // Create an audio configuration resource. |
| 60 pp::AudioConfig audio_config = pp::AudioConfig(instance_, | 64 pp::AudioConfig audio_config = pp::AudioConfig( |
| 61 sample_rate, | 65 instance_, sample_rate, samples_per_frame_); |
| 62 samples_per_frame_); | |
| 63 | 66 |
| 64 // Create an audio resource. | 67 // Create an audio resource. |
| 65 audio_ = pp::Audio(instance_, audio_config, PepperAudioPlayerCallback, this); | 68 audio_ = pp::Audio(instance_, audio_config, PepperAudioPlayerCallback, this); |
| 66 | 69 |
| 67 // Immediately start the player. | 70 // Immediately start the player. |
| 68 bool success = audio_.StartPlayback(); | 71 bool success = audio_.StartPlayback(); |
| 69 if (!success) | 72 if (!success) |
| 70 LOG(ERROR) << "Failed to start Pepper audio player"; | 73 LOG(ERROR) << "Failed to start Pepper audio player"; |
| 71 return success; | 74 return success; |
| 72 } | 75 } |
| 73 | 76 |
| 74 void PepperAudioPlayer::ProcessAudioPacket(scoped_ptr<AudioPacket> packet) { | 77 void PepperAudioPlayer::ProcessAudioPacket(scoped_ptr<AudioPacket> packet) { |
| 75 // TODO(kxing): Limit the size of the queue so that latency doesn't grow | |
| 76 // too large. | |
| 77 | |
| 78 CHECK_EQ(1, packet->data_size()); | 78 CHECK_EQ(1, packet->data_size()); |
| 79 DCHECK_EQ(AudioPacket::ENCODING_RAW, packet->encoding()); | 79 DCHECK_EQ(AudioPacket::ENCODING_RAW, packet->encoding()); |
| 80 DCHECK_NE(AudioPacket::SAMPLING_RATE_INVALID, packet->sampling_rate()); | 80 DCHECK_NE(AudioPacket::SAMPLING_RATE_INVALID, packet->sampling_rate()); |
| 81 DCHECK_EQ(kSampleSizeBytes, packet->bytes_per_sample()); | 81 DCHECK_EQ(kSampleSizeBytes, packet->bytes_per_sample()); |
| 82 DCHECK_EQ(static_cast<int>(kChannels), packet->channels()); | 82 DCHECK_EQ(static_cast<int>(kChannels), packet->channels()); |
| 83 | 83 DCHECK_EQ(packet->data(0).size() % (kChannels * kSampleSizeBytes), 0u); |
|
Wez
2012/09/12 20:47:57
Is this check correct; do we not allow splitting o
Sergey Ulanov
2012/09/12 21:43:34
Yes, it's correct. There is no way you can encode/
| |
| 84 if (packet->data(0).size() % (kChannels * kSampleSizeBytes) != 0) { | |
| 85 LOG(WARNING) << "Received corrupted packet."; | |
| 86 return; | |
| 87 } | |
| 88 base::AutoLock auto_lock(lock_); | |
| 89 | 84 |
| 90 // No-op if the Pepper player won't start. | 85 // No-op if the Pepper player won't start. |
| 91 if (start_failed_) { | 86 if (start_failed_) { |
| 92 return; | 87 return; |
| 93 } | 88 } |
| 94 | 89 |
| 95 // Start the Pepper audio player if this is the first packet. | 90 // Start the Pepper audio player if this is the first packet. |
| 96 if (sampling_rate_ != packet->sampling_rate()) { | 91 if (sampling_rate_ != packet->sampling_rate()) { |
| 97 // Drop all packets currently in the queue, since they are sampled at the | 92 // Drop all packets currently in the queue, since they are sampled at the |
| 98 // wrong rate. | 93 // wrong rate. |
| 99 STLDeleteElements(&queued_packets_); | 94 { |
| 95 base::AutoLock auto_lock(lock_); | |
| 96 STLDeleteElements(&queued_packets_); | |
| 97 queued_samples_ = 0; | |
| 98 } | |
| 100 | 99 |
| 101 bool success = ResetAudioPlayer(packet->sampling_rate()); | 100 bool success = ResetAudioPlayer(packet->sampling_rate()); |
| 102 if (!success) { | 101 if (!success) { |
| 103 start_failed_ = true; | 102 start_failed_ = true; |
| 104 return; | 103 return; |
| 105 } | 104 } |
| 106 } | 105 } |
| 107 | 106 |
| 107 base::AutoLock auto_lock(lock_); | |
| 108 | |
| 109 if (queued_samples_ > kMaxQueueLatencyMs * sampling_rate_ / | |
| 110 base::Time::kMillisecondsPerSecond) { | |
| 111 STLDeleteElements(&queued_packets_); | |
| 112 queued_samples_ = 0; | |
| 113 } | |
| 114 | |
| 115 queued_samples_ += packet->data(0).size() / (kChannels * kSampleSizeBytes); | |
|
Wez
2012/09/12 20:47:57
nit: Since you use kSampleSizeBytes * kChannels in
Sergey Ulanov
2012/09/12 21:43:34
Done. I wish there was a term for set of samples f
| |
| 108 queued_packets_.push_back(packet.release()); | 116 queued_packets_.push_back(packet.release()); |
| 109 } | 117 } |
| 110 | 118 |
| 111 // static | 119 // static |
| 112 void PepperAudioPlayer::PepperAudioPlayerCallback(void* samples, | 120 void PepperAudioPlayer::PepperAudioPlayerCallback(void* samples, |
| 113 uint32_t buffer_size, | 121 uint32_t buffer_size, |
| 114 void* data) { | 122 void* data) { |
| 115 PepperAudioPlayer* audio_player = static_cast<PepperAudioPlayer*>(data); | 123 PepperAudioPlayer* audio_player = static_cast<PepperAudioPlayer*>(data); |
| 116 audio_player->FillWithSamples(samples, buffer_size); | 124 audio_player->FillWithSamples(samples, buffer_size); |
| 117 } | 125 } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 145 | 153 |
| 146 const std::string& packet_data = queued_packets_.front()->data(0); | 154 const std::string& packet_data = queued_packets_.front()->data(0); |
| 147 size_t bytes_to_copy = std::min( | 155 size_t bytes_to_copy = std::min( |
| 148 packet_data.size() - bytes_consumed_, | 156 packet_data.size() - bytes_consumed_, |
| 149 bytes_needed - bytes_extracted); | 157 bytes_needed - bytes_extracted); |
| 150 memcpy(next_sample, packet_data.data() + bytes_consumed_, bytes_to_copy); | 158 memcpy(next_sample, packet_data.data() + bytes_consumed_, bytes_to_copy); |
| 151 | 159 |
| 152 next_sample += bytes_to_copy; | 160 next_sample += bytes_to_copy; |
| 153 bytes_consumed_ += bytes_to_copy; | 161 bytes_consumed_ += bytes_to_copy; |
| 154 bytes_extracted += bytes_to_copy; | 162 bytes_extracted += bytes_to_copy; |
| 163 queued_samples_ -= bytes_to_copy / kSampleSizeBytes / kChannels; | |
| 164 DCHECK_GE(queued_samples_, 0); | |
| 155 } | 165 } |
| 156 } | 166 } |
| 157 | 167 |
| 158 } // namespace remoting | 168 } // namespace remoting |
| OLD | NEW |