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

Side by Side Diff: media/cast/sender/audio_encoder.cc

Issue 601413003: [cast] AAC encoder for OS X and iOS based on AudioConverter and AudioFile (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@audio-remove-constants
Patch Set: A lot of comment editing to document the implementation, an important output corruption fix and uni… Created 6 years, 2 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/cast/sender/audio_encoder.h ('k') | media/cast/sender/audio_encoder_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 "media/cast/sender/audio_encoder.h" 5 #include "media/cast/sender/audio_encoder.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits>
9 #include <string>
8 10
9 #include "base/bind.h" 11 #include "base/bind.h"
10 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
11 #include "base/location.h" 13 #include "base/location.h"
12 #include "base/stl_util.h" 14 #include "base/stl_util.h"
13 #include "base/sys_byteorder.h" 15 #include "base/sys_byteorder.h"
14 #include "base/time/time.h" 16 #include "base/time/time.h"
15 #include "media/base/audio_bus.h" 17 #include "media/base/audio_bus.h"
16 #include "media/cast/cast_defines.h" 18 #include "media/cast/cast_defines.h"
17 #include "media/cast/cast_environment.h" 19 #include "media/cast/cast_environment.h"
20
21 #if !defined(OS_IOS)
18 #include "third_party/opus/src/include/opus.h" 22 #include "third_party/opus/src/include/opus.h"
23 #endif
24
25 #if defined(OS_MACOSX)
26 #include <AudioToolbox/AudioToolbox.h>
27 #endif
19 28
20 namespace { 29 namespace {
21 30
22 const int kUnderrunSkipThreshold = 3; 31 const int kUnderrunSkipThreshold = 3;
23 const int kDefaultFramesPerSecond = 100; 32 const int kDefaultFramesPerSecond = 100;
24 33
25 } // namespace 34 } // namespace
26 35
27 namespace media { 36 namespace media {
28 namespace cast { 37 namespace cast {
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 // the RTP timestamps. 199 // the RTP timestamps.
191 base::TimeTicks frame_capture_time_; 200 base::TimeTicks frame_capture_time_;
192 201
193 // Set to non-zero to indicate the next output frame skipped over audio 202 // Set to non-zero to indicate the next output frame skipped over audio
194 // samples in order to recover from an input underrun. 203 // samples in order to recover from an input underrun.
195 int samples_dropped_from_buffer_; 204 int samples_dropped_from_buffer_;
196 205
197 DISALLOW_COPY_AND_ASSIGN(ImplBase); 206 DISALLOW_COPY_AND_ASSIGN(ImplBase);
198 }; 207 };
199 208
209 #if !defined(OS_IOS)
200 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase { 210 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase {
201 public: 211 public:
202 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, 212 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment,
203 int num_channels, 213 int num_channels,
204 int sampling_rate, 214 int sampling_rate,
205 int bitrate, 215 int bitrate,
206 const FrameEncodedCallback& callback) 216 const FrameEncodedCallback& callback)
207 : ImplBase(cast_environment, 217 : ImplBase(cast_environment,
208 CODEC_AUDIO_OPUS, 218 CODEC_AUDIO_OPUS,
209 num_channels, 219 num_channels,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 // This is the recommended value, according to documentation in 304 // This is the recommended value, according to documentation in
295 // third_party/opus/src/include/opus.h, so that the Opus encoder does not 305 // third_party/opus/src/include/opus.h, so that the Opus encoder does not
296 // degrade the audio due to memory constraints. 306 // degrade the audio due to memory constraints.
297 // 307 //
298 // Note: Whereas other RTP implementations do not, the cast library is 308 // Note: Whereas other RTP implementations do not, the cast library is
299 // perfectly capable of transporting larger than MTU-sized audio frames. 309 // perfectly capable of transporting larger than MTU-sized audio frames.
300 static const int kOpusMaxPayloadSize = 4000; 310 static const int kOpusMaxPayloadSize = 4000;
301 311
302 DISALLOW_COPY_AND_ASSIGN(OpusImpl); 312 DISALLOW_COPY_AND_ASSIGN(OpusImpl);
303 }; 313 };
314 #endif
315
316 #if defined(OS_MACOSX)
317 class AudioEncoder::AppleAacImpl : public AudioEncoder::ImplBase {
318 // AAC-LC has two access unit sizes (960 and 1024). The Apple encoder only
319 // supports the latter.
320 static const int AccessUnitSamples = 1024;
miu 2014/10/22 05:05:28 Chromium style: Constants start with k, so this sh
321
322 // Size of an ADTS header (w/o checksum). See
323 // http://wiki.multimedia.cx/index.php?title=ADTS
324 static const int AdtsHeaderSize = 7;
miu 2014/10/22 05:05:28 kAdtsHeaderSize
325
326 public:
327 AppleAacImpl(const scoped_refptr<CastEnvironment>& cast_environment,
328 int num_channels,
329 int sampling_rate,
330 int bitrate,
331 const FrameEncodedCallback& callback)
332 : ImplBase(cast_environment,
333 CODEC_AUDIO_AAC,
334 num_channels,
335 sampling_rate,
336 AccessUnitSamples,
337 callback),
338 input_buffer_(AudioBus::Create(num_channels, AccessUnitSamples)),
339 input_bus_(AudioBus::CreateWrapper(num_channels)),
340 max_access_unit_size_(0),
341 output_buffer_(nullptr),
342 converter_(nullptr),
343 file_(nullptr),
344 num_access_units_(0),
345 can_resume_(true) {
346 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) {
347 return;
348 }
349 if (!Initialize(sampling_rate, bitrate)) {
350 ImplBase::cast_initialization_status_ =
351 STATUS_INVALID_AUDIO_CONFIGURATION;
352 return;
353 }
354 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED;
355 }
356
357 private:
358 virtual ~AppleAacImpl() { Teardown(); }
359
360 // Destroys the existing audio converter and file, if any.
361 void Teardown() {
362 if (converter_) {
363 AudioConverterDispose(converter_);
364 converter_ = nullptr;
365 }
366 if (file_) {
367 AudioFileClose(file_);
368 file_ = nullptr;
369 }
370 }
371
372 // Initializes the audio converter and file. Calls Teardown to destroy any
373 // existing state. This is so that Initialize() may be called to setup another
374 // converter after a non-resumable interruption.
375 bool Initialize(int sampling_rate, int bitrate) {
376 // Teardown previous audio converter and file.
377 Teardown();
378
379 // Input data comes from AudioBus objects, which carry non-interleaved
380 // packed native-endian float samples. Note that in Core Audio, a frame is
381 // one sample across all channels at a given point in time. When describing
382 // a non-interleaved samples format, the "per frame" fields mean "per
383 // channel" or "per stream", with the exception of |mChannelsPerFrame|. For
384 // uncompressed formats, one packet contains one frame.
385 AudioStreamBasicDescription in_asbd;
386 in_asbd.mSampleRate = sampling_rate;
387 in_asbd.mFormatID = kAudioFormatLinearPCM;
388 in_asbd.mFormatFlags =
389 kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
390 in_asbd.mChannelsPerFrame = num_channels_;
391 in_asbd.mBitsPerChannel = sizeof(float) * 8;
392 in_asbd.mFramesPerPacket = 1;
393 in_asbd.mBytesPerPacket = in_asbd.mBytesPerFrame = sizeof(float);
394 in_asbd.mReserved = 0;
395
396 // Request AAC-LC encoding, with no downmixing or downsampling.
397 AudioStreamBasicDescription out_asbd;
398 memset(&out_asbd, 0, sizeof(AudioStreamBasicDescription));
399 out_asbd.mSampleRate = sampling_rate;
400 out_asbd.mFormatID = kAudioFormatMPEG4AAC;
401 out_asbd.mChannelsPerFrame = num_channels_;
402 UInt32 prop_size = sizeof(out_asbd);
403 if (AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
404 0,
405 nullptr,
406 &prop_size,
407 &out_asbd) != noErr) {
408 return false;
409 }
410
411 if (AudioConverterNew(&in_asbd, &out_asbd, &converter_) != noErr) {
412 return false;
413 }
414
415 // The converter will fully specify the output format and update the
416 // relevant fields of the structure, which we can now query.
417 prop_size = sizeof(out_asbd);
418 if (AudioConverterGetProperty(converter_,
419 kAudioConverterCurrentOutputStreamDescription,
420 &prop_size,
421 &out_asbd) != noErr) {
422 return false;
423 }
424
425 // If bitrate is <= 0, allow the encoder to pick a suitable value.
426 // Otherwise, set the bitrate (which can fail if the value is not suitable
427 // or compatible with the output sampling rate or channels).
428 if (bitrate > 0) {
429 prop_size = sizeof(int);
430 if (AudioConverterSetProperty(
431 converter_, kAudioConverterEncodeBitRate, prop_size, &bitrate) !=
432 noErr) {
433 return false;
434 }
435 }
436
437 #if defined(OS_IOS)
438 // See the comment next to |can_resume_| for details on resumption. Some
439 // converters can return kAudioConverterErr_PropertyNotSupported, in which
440 // case resumption is implicitly supported. This is the only location where
441 // the implementation modifies |can_resume_|.
442 uint32_t can_resume;
443 prop_size = sizeof(can_resume);
444 OSStatus oserr = AudioConverterGetProperty(
445 converter_,
446 kAudioConverterPropertyCanResumeFromInterruption,
447 &prop_size,
448 &can_resume);
449 if (oserr == noErr) {
450 const_cast<bool&>(can_resume_) = can_resume != 0;
451 }
452 #endif
453
454 // Figure out the maximum size of an access unit that the encoder can
455 // produce. |mBytesPerPacket| will be 0 for variable size configurations,
456 // in which case we must query the value.
457 uint32_t max_access_unit_size = out_asbd.mBytesPerPacket;
458 if (max_access_unit_size == 0) {
459 prop_size = sizeof(max_access_unit_size);
460 if (AudioConverterGetProperty(
461 converter_,
462 kAudioConverterPropertyMaximumOutputPacketSize,
463 &prop_size,
464 &max_access_unit_size) != noErr) {
465 return false;
466 }
467 }
468
469 // This is the only location where the implementation modifies
470 // |max_access_unit_size_|.
471 const_cast<uint32_t&>(max_access_unit_size_) = max_access_unit_size;
472
473 // Allocate a buffer to store one access unit. This is the only location
474 // where the implementation modifies |access_unit_buffer_|.
475 const_cast<scoped_ptr<uint8[]>&>(access_unit_buffer_)
476 .reset(new uint8[max_access_unit_size]);
477
478 // Initialize the converter ABL. Note that the buffer size has to be set
479 // before every encode operation, since the field is modified to indicate
480 // the size of the output data (on input it indicates the buffer capacity).
481 converter_abl_.mNumberBuffers = 1;
482 converter_abl_.mBuffers[0].mNumberChannels = num_channels_;
483 converter_abl_.mBuffers[0].mData = access_unit_buffer_.get();
484
485 // The "magic cookie" is an encoder state vector required for decoding and
486 // packetization. It is queried now from |converter_| then set on |file_|
487 // after initialization.
488 UInt32 cookie_size;
489 if (AudioConverterGetPropertyInfo(converter_,
490 kAudioConverterCompressionMagicCookie,
491 &cookie_size,
492 nullptr) != noErr) {
493 return false;
494 }
495 scoped_ptr<uint8[]> cookie_data(new uint8[cookie_size]);
496 if (AudioConverterGetProperty(converter_,
497 kAudioConverterCompressionMagicCookie,
498 &cookie_size,
499 cookie_data.get()) != noErr) {
500 return false;
501 }
502
503 if (AudioFileInitializeWithCallbacks(this,
504 nullptr,
505 &FileWriteCallback,
506 nullptr,
507 nullptr,
508 kAudioFileAAC_ADTSType,
509 &out_asbd,
510 0,
511 &file_) != noErr) {
512 return false;
513 }
514
515 if (AudioFileSetProperty(file_,
516 kAudioFilePropertyMagicCookieData,
517 cookie_size,
518 cookie_data.get()) != noErr) {
519 return false;
520 }
521
522 // Initially the input bus points to the input buffer. See the comment on
523 // |input_bus_| for more on this optimization.
524 input_bus_->set_frames(AccessUnitSamples);
525 for (int ch = 0; ch < input_buffer_->channels(); ++ch) {
526 input_bus_->SetChannelData(ch, input_buffer_->channel(ch));
527 }
528
529 return true;
530 }
531
532 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
533 int source_offset,
534 int buffer_fill_offset,
535 int num_samples) override {
536 DCHECK_EQ(audio_bus->channels(), input_buffer_->channels());
537
538 // See the comment on |input_bus_| for more on this optimization. Note that
539 // we cannot elide the copy if the source offset would result in an
540 // unaligned pointer.
541 if (num_samples == AccessUnitSamples &&
542 source_offset * sizeof(float) % AudioBus::kChannelAlignment == 0) {
543 DCHECK_EQ(buffer_fill_offset, 0);
544 for (int ch = 0; ch < audio_bus->channels(); ++ch) {
545 auto samples = const_cast<float*>(audio_bus->channel(ch));
546 input_bus_->SetChannelData(ch, samples + source_offset);
547 }
548 return;
549 }
550
551 // Copy the samples into the input buffer.
552 DCHECK_EQ(input_bus_->channel(0), input_buffer_->channel(0));
553 audio_bus->CopyPartialFramesTo(
554 source_offset, num_samples, buffer_fill_offset, input_buffer_.get());
555 }
556
557 virtual bool EncodeFromFilledBuffer(std::string* out) override {
558 // Reset the buffer size field to the buffer capacity.
559 converter_abl_.mBuffers[0].mDataByteSize = max_access_unit_size_;
560
561 // Encode the current input buffer. This is a sychronous call.
562 OSStatus oserr;
563 UInt32 io_num_packets = 1;
564 AudioStreamPacketDescription packet_description;
565 oserr = AudioConverterFillComplexBuffer(converter_,
566 &ConverterFillDataCallback,
567 this,
568 &io_num_packets,
569 &converter_abl_,
570 &packet_description);
571 if (oserr != noErr || io_num_packets == 0) {
572 return false;
573 }
574
575 // Reserve space in the output buffer to write the packet.
576 out->reserve(packet_description.mDataByteSize + AdtsHeaderSize);
577
578 // Set the current output buffer and emit an ADTS-wrapped AAC access unit.
579 // This is a synchronous call. After it returns, reset the output buffer.
580 output_buffer_ = out;
581 oserr = AudioFileWritePackets(file_,
582 false,
583 converter_abl_.mBuffers[0].mDataByteSize,
584 &packet_description,
585 num_access_units_,
586 &io_num_packets,
587 converter_abl_.mBuffers[0].mData);
588 output_buffer_ = nullptr;
589 if (oserr != noErr || io_num_packets == 0) {
590 return false;
591 }
592 num_access_units_ += io_num_packets;
593 return true;
594 }
595
596 // The |AudioConverterFillComplexBuffer| input callback function. Configures
597 // the provided |AudioBufferList| to alias |input_bus_|. The implementation
598 // can only supply |AccessUnitSamples| samples as a result of not copying
599 // samples or tracking read and write positions. Note that this function is
600 // called synchronously by |AudioConverterFillComplexBuffer|.
601 static OSStatus ConverterFillDataCallback(
602 AudioConverterRef in_converter,
603 UInt32* io_num_packets,
604 AudioBufferList* io_data,
605 AudioStreamPacketDescription** out_packet_desc,
606 void* in_encoder) {
607 DCHECK(in_encoder);
608 auto encoder = reinterpret_cast<AppleAacImpl*>(in_encoder);
609 auto input_buffer = encoder->input_buffer_.get();
610 auto input_bus = encoder->input_bus_.get();
611
612 DCHECK(*io_num_packets == AccessUnitSamples);
miu 2014/10/22 05:05:28 nit: DCHECK_EQ(*io_num_packets, static_cast<unsign
613 DCHECK_EQ(io_data->mNumberBuffers,
614 static_cast<unsigned>(input_bus->channels()));
615 for (int i_buf = 0, end = io_data->mNumberBuffers; i_buf < end; ++i_buf) {
616 io_data->mBuffers[i_buf].mNumberChannels = 1;
617 io_data->mBuffers[i_buf].mDataByteSize = sizeof(float) * *io_num_packets;
618 io_data->mBuffers[i_buf].mData = input_bus->channel(i_buf);
619
620 // Reset the input bus back to the input buffer. See the comment on
621 // |input_bus_| for more on this optimization.
622 input_bus->SetChannelData(i_buf, input_buffer->channel(i_buf));
623 }
624 return noErr;
625 }
626
627 // The AudioFile write callback function. Appends the data to the encoder's
628 // current |output_buffer_|.
629 static OSStatus FileWriteCallback(void* in_encoder,
630 SInt64 in_position,
631 UInt32 in_size,
632 const void* in_buffer,
633 UInt32* out_size) {
634 DCHECK(in_encoder);
635 DCHECK(in_buffer);
636 auto encoder = reinterpret_cast<const AppleAacImpl*>(in_encoder);
637 auto buffer = reinterpret_cast<const std::string::value_type*>(in_buffer);
638
639 std::string* const output_buffer = encoder->output_buffer_;
640 DCHECK(output_buffer);
641
642 output_buffer->append(buffer, in_size);
643 *out_size = in_size;
644 return noErr;
645 }
646
647 // Buffer that holds one AAC access unit worth of samples. The input callback
648 // function provides samples from this buffer via |input_bus_| to the encoder.
649 const scoped_ptr<AudioBus> input_buffer_;
650
651 // Wrapper AudioBus used by the input callback function. Normally it wraps
652 // |input_buffer_|. However, as an optimization when the client submits a
653 // buffer containing exactly one access unit worth of samples, the bus is
654 // redirected to the client buffer temporarily. We know that the base
655 // implementation will call us right after to encode the buffer and thus we
656 // can eliminate the copy into |input_buffer_|.
657 const scoped_ptr<AudioBus> input_bus_;
658
659 // A buffer that holds one AAC access unit. Initialized in |Initialize| once
660 // the maximum access unit size is known.
661 const scoped_ptr<uint8[]> access_unit_buffer_;
662
663 // The maximum size of an access unit that the encoder can emit.
664 const uint32_t max_access_unit_size_;
665
666 // A temporary pointer to the current output buffer. Only non-null when
667 // writing an access unit. Accessed by the AudioFile write callback function.
668 std::string* output_buffer_;
669
670 // The |AudioConverter| is responsible for AAC encoding. This is a Core Audio
671 // object, not to be confused with |media::AudioConverter|.
672 AudioConverterRef converter_;
673
674 // The |AudioFile| is responsible for ADTS packetization.
675 AudioFileID file_;
676
677 // An |AudioBufferList| passed to the converter to store encoded samples.
678 AudioBufferList converter_abl_;
679
680 // The number of access units emitted so far by the encoder.
681 uint64_t num_access_units_;
682
683 // On iOS, audio codecs can be interrupted by other services (such as an
684 // audio alert or phone call). Depending on the underlying hardware and
685 // configuration, the codec may have to be thrown away and re-initialized
686 // after such an interruption. This flag tracks if we can resume or not from
687 // such an interruption. It is initialized to true, which is the only possible
688 // value on OS X and on most modern iOS hardware.
689 // TODO(jfroy): Implement encoder re-initialization after interruption.
690 // https://crbug.com/424787
691 const bool can_resume_;
692
693 DISALLOW_COPY_AND_ASSIGN(AppleAacImpl);
694 };
695 #endif // defined(OS_MACOSX)
304 696
305 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase { 697 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase {
306 public: 698 public:
307 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, 699 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment,
308 int num_channels, 700 int num_channels,
309 int sampling_rate, 701 int sampling_rate,
310 const FrameEncodedCallback& callback) 702 const FrameEncodedCallback& callback)
311 : ImplBase(cast_environment, 703 : ImplBase(cast_environment,
312 CODEC_AUDIO_PCM16, 704 CODEC_AUDIO_PCM16,
313 num_channels, 705 num_channels,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 int num_channels, 748 int num_channels,
357 int sampling_rate, 749 int sampling_rate,
358 int bitrate, 750 int bitrate,
359 Codec codec, 751 Codec codec,
360 const FrameEncodedCallback& frame_encoded_callback) 752 const FrameEncodedCallback& frame_encoded_callback)
361 : cast_environment_(cast_environment) { 753 : cast_environment_(cast_environment) {
362 // Note: It doesn't matter which thread constructs AudioEncoder, just so long 754 // Note: It doesn't matter which thread constructs AudioEncoder, just so long
363 // as all calls to InsertAudio() are by the same thread. 755 // as all calls to InsertAudio() are by the same thread.
364 insert_thread_checker_.DetachFromThread(); 756 insert_thread_checker_.DetachFromThread();
365 switch (codec) { 757 switch (codec) {
758 #if !defined(OS_IOS)
366 case CODEC_AUDIO_OPUS: 759 case CODEC_AUDIO_OPUS:
367 impl_ = new OpusImpl(cast_environment, 760 impl_ = new OpusImpl(cast_environment,
368 num_channels, 761 num_channels,
369 sampling_rate, 762 sampling_rate,
370 bitrate, 763 bitrate,
371 frame_encoded_callback); 764 frame_encoded_callback);
372 break; 765 break;
766 #endif
767 #if defined(OS_MACOSX)
768 case CODEC_AUDIO_AAC:
769 impl_ = new AppleAacImpl(cast_environment,
770 num_channels,
771 sampling_rate,
772 bitrate,
773 frame_encoded_callback);
774 break;
775 #endif // defined(OS_MACOSX)
373 case CODEC_AUDIO_PCM16: 776 case CODEC_AUDIO_PCM16:
374 impl_ = new Pcm16Impl(cast_environment, 777 impl_ = new Pcm16Impl(cast_environment,
375 num_channels, 778 num_channels,
376 sampling_rate, 779 sampling_rate,
377 frame_encoded_callback); 780 frame_encoded_callback);
378 break; 781 break;
379 default: 782 default:
380 NOTREACHED() << "Unsupported or unspecified codec for audio encoder"; 783 NOTREACHED() << "Unsupported or unspecified codec for audio encoder";
381 break; 784 break;
382 } 785 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 cast_environment_->PostTask(CastEnvironment::AUDIO, 824 cast_environment_->PostTask(CastEnvironment::AUDIO,
422 FROM_HERE, 825 FROM_HERE,
423 base::Bind(&AudioEncoder::ImplBase::EncodeAudio, 826 base::Bind(&AudioEncoder::ImplBase::EncodeAudio,
424 impl_, 827 impl_,
425 base::Passed(&audio_bus), 828 base::Passed(&audio_bus),
426 recorded_time)); 829 recorded_time));
427 } 830 }
428 831
429 } // namespace cast 832 } // namespace cast
430 } // namespace media 833 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/sender/audio_encoder.h ('k') | media/cast/sender/audio_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698