OLD | NEW |
---|---|
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 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/location.h" | 11 #include "base/location.h" |
12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "base/sys_byteorder.h" | 13 #include "base/sys_byteorder.h" |
14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
15 #include "media/base/audio_bus.h" | 15 #include "media/base/audio_bus.h" |
16 #include "media/cast/cast_defines.h" | 16 #include "media/cast/cast_defines.h" |
17 #include "media/cast/cast_environment.h" | 17 #include "media/cast/cast_environment.h" |
18 | |
19 #if !defined(OS_IOS) | |
18 #include "third_party/opus/src/include/opus.h" | 20 #include "third_party/opus/src/include/opus.h" |
21 #endif | |
22 | |
23 #if defined(OS_MACOSX) | |
24 #include <AudioToolbox/AudioToolbox.h> | |
25 #endif | |
19 | 26 |
20 namespace media { | 27 namespace media { |
21 namespace cast { | 28 namespace cast { |
22 | 29 |
23 | 30 |
24 // Base class that handles the common problem of feeding one or more AudioBus' | 31 // Base class that handles the common problem of feeding one or more AudioBus' |
25 // data into a buffer and then, once the buffer is full, encoding the signal and | 32 // data into a buffer and then, once the buffer is full, encoding the signal and |
26 // emitting an EncodedFrame via the FrameEncodedCallback. | 33 // emitting an EncodedFrame via the FrameEncodedCallback. |
27 // | 34 // |
28 // Subclasses complete the implementation by handling the actual encoding | 35 // Subclasses complete the implementation by handling the actual encoding |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 // the RTP timestamps. | 199 // the RTP timestamps. |
193 base::TimeTicks frame_capture_time_; | 200 base::TimeTicks frame_capture_time_; |
194 | 201 |
195 // 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 |
196 // samples in order to recover from an input underrun. | 203 // samples in order to recover from an input underrun. |
197 int samples_dropped_from_buffer_; | 204 int samples_dropped_from_buffer_; |
198 | 205 |
199 DISALLOW_COPY_AND_ASSIGN(ImplBase); | 206 DISALLOW_COPY_AND_ASSIGN(ImplBase); |
200 }; | 207 }; |
201 | 208 |
209 #if !defined(OS_IOS) | |
202 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase { | 210 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase { |
203 public: | 211 public: |
204 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, | 212 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, |
205 int num_channels, | 213 int num_channels, |
206 int sampling_rate, | 214 int sampling_rate, |
207 int bitrate, | 215 int bitrate, |
208 const FrameEncodedCallback& callback) | 216 const FrameEncodedCallback& callback) |
209 : ImplBase(cast_environment, | 217 : ImplBase(cast_environment, |
210 CODEC_AUDIO_OPUS, | 218 CODEC_AUDIO_OPUS, |
211 num_channels, | 219 num_channels, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 // This is the recommended value, according to documentation in | 291 // This is the recommended value, according to documentation in |
284 // third_party/opus/src/include/opus.h, so that the Opus encoder does not | 292 // third_party/opus/src/include/opus.h, so that the Opus encoder does not |
285 // degrade the audio due to memory constraints. | 293 // degrade the audio due to memory constraints. |
286 // | 294 // |
287 // Note: Whereas other RTP implementations do not, the cast library is | 295 // Note: Whereas other RTP implementations do not, the cast library is |
288 // perfectly capable of transporting larger than MTU-sized audio frames. | 296 // perfectly capable of transporting larger than MTU-sized audio frames. |
289 static const int kOpusMaxPayloadSize = 4000; | 297 static const int kOpusMaxPayloadSize = 4000; |
290 | 298 |
291 DISALLOW_COPY_AND_ASSIGN(OpusImpl); | 299 DISALLOW_COPY_AND_ASSIGN(OpusImpl); |
292 }; | 300 }; |
301 #endif | |
302 | |
303 #if defined(OS_MACOSX) | |
304 class AudioEncoder::AacAudioConverterImpl : public AudioEncoder::ImplBase { | |
305 public: | |
306 AacAudioConverterImpl(const scoped_refptr<CastEnvironment>& cast_environment, | |
307 int num_channels, | |
308 int sampling_rate, | |
309 int bitrate, | |
310 const FrameEncodedCallback& callback) | |
311 : ImplBase(cast_environment, | |
312 CODEC_AUDIO_AAC, | |
313 num_channels, | |
314 sampling_rate, | |
315 1024, /* AudioConverter produces 1024 samples blocks */ | |
miu
2014/09/29 19:54:47
s/AudioConverter/AacImpl/
| |
316 callback), | |
317 input_buffer_(AudioBus::Create(num_channels, 1024)), | |
318 output_buffer_(nullptr), | |
319 converter_(nullptr), | |
320 file_(nullptr), | |
321 num_encoded_packets_(0), | |
322 max_packet_size_(0), | |
323 can_resume_(true) { | |
324 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) { | |
325 return; | |
326 } | |
327 if (!Initialize(sampling_rate, bitrate)) { | |
328 ImplBase::cast_initialization_status_ = | |
329 STATUS_INVALID_AUDIO_CONFIGURATION; | |
330 return; | |
331 } | |
332 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED; | |
333 } | |
334 | |
335 private: | |
336 // The |AudioConverterFillComplexBuffer| input callback function. Returns the | |
337 // data that has been copied into the encoder's |buffer_| by the | |
338 // |TransferSamplesIntoBuffer| method. | |
miu
2014/09/29 19:54:47
Just a sanity-check: This callback is called synch
jfroy
2014/10/14 01:06:34
Yep. I'll add the comment.
| |
339 static OSStatus ConverterFillDataCallback( | |
miu
2014/09/29 19:54:47
style nit: static methods need to be declared/defi
| |
340 AudioConverterRef in_converter, | |
341 UInt32* io_num_packets, | |
342 AudioBufferList* io_data, | |
343 AudioStreamPacketDescription** out_packet_desc, | |
344 void* in_encoder) { | |
345 DCHECK(io_data); | |
346 DCHECK(in_encoder); | |
347 auto encoder = reinterpret_cast<const AacAudioConverterImpl*>(in_encoder); | |
348 | |
349 // Provide the entire content of the input buffer. | |
350 const int num_frames = encoder->input_buffer_->frames(); | |
351 *io_num_packets = num_frames; | |
352 | |
353 DCHECK_EQ(io_data->mNumberBuffers, | |
354 static_cast<unsigned>(encoder->input_buffer_->channels())); | |
355 for (int i_buf = 0, end = io_data->mNumberBuffers; i_buf < end; ++i_buf) { | |
356 io_data->mBuffers[i_buf].mNumberChannels = 1; | |
357 io_data->mBuffers[i_buf].mDataByteSize = sizeof(float) * num_frames; | |
358 io_data->mBuffers[i_buf].mData = encoder->input_buffer_->channel(i_buf); | |
359 } | |
360 return noErr; | |
361 } | |
362 | |
363 // The AudioFile write callback function. Appends the data to the encoder's | |
364 // current output buffer. | |
365 static OSStatus FileWriteCallback(void* in_encoder, | |
366 SInt64 in_position, | |
367 UInt32 in_size, | |
368 const void* in_buffer, | |
369 UInt32* out_size) { | |
370 DCHECK(in_encoder); | |
371 auto encoder = reinterpret_cast<const AacAudioConverterImpl*>(in_encoder); | |
372 DCHECK(in_buffer); | |
373 auto buffer = reinterpret_cast<const std::string::value_type*>(in_buffer); | |
374 | |
375 std::string* const output_buffer = encoder->output_buffer_; | |
376 DCHECK(output_buffer); | |
377 | |
378 output_buffer->append(buffer, in_size); | |
379 *out_size = in_size; | |
380 return noErr; | |
381 } | |
382 | |
383 virtual ~AacAudioConverterImpl() { Teardown(); } | |
384 | |
385 // Destroys the existing audio converter and file, if any. | |
386 void Teardown() { | |
387 if (converter_) { | |
388 AudioConverterDispose(converter_); | |
389 converter_ = nullptr; | |
390 } | |
391 if (file_) { | |
392 AudioFileClose(file_); | |
393 file_ = nullptr; | |
394 } | |
395 } | |
396 | |
397 // Initializes the audio converter and file. Calls Teardown to destroy any | |
398 // existing state. This is so that Initialize() may be called to setup another | |
399 // converter after a non-resumable interruption. | |
400 bool Initialize(int sampling_rate, int bitrate) { | |
401 // Teardown previous audio converter and file. | |
402 Teardown(); | |
403 | |
404 // Input data comes from AudioBus objects, which carry deinterleaved packed | |
405 // native-endian float samples. | |
406 AudioStreamBasicDescription in_asbd; | |
407 in_asbd.mSampleRate = sampling_rate; | |
408 in_asbd.mFormatID = kAudioFormatLinearPCM; | |
409 in_asbd.mFormatFlags = | |
410 kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; | |
411 in_asbd.mChannelsPerFrame = num_channels_; | |
412 in_asbd.mBitsPerChannel = sizeof(float) * 8; | |
413 in_asbd.mFramesPerPacket = 1; | |
414 in_asbd.mBytesPerPacket = in_asbd.mBytesPerFrame = sizeof(float); | |
miu
2014/09/29 19:54:47
Somehow, this doesn't seem right. Only 4 bytes pe
jfroy
2014/10/14 01:06:34
In Core Audio, a frame of audio is one sample acro
| |
415 in_asbd.mReserved = 0; | |
416 | |
417 // Request AAC-LC encoding, with no downmixing or downsampling. | |
418 AudioStreamBasicDescription out_asbd; | |
419 memset(&out_asbd, 0, sizeof(AudioStreamBasicDescription)); | |
420 out_asbd.mSampleRate = sampling_rate; | |
421 out_asbd.mFormatID = kAudioFormatMPEG4AAC; | |
422 out_asbd.mChannelsPerFrame = num_channels_; | |
423 UInt32 prop_size = sizeof(out_asbd); | |
424 if (AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, | |
425 0, | |
426 nullptr, | |
427 &prop_size, | |
428 &out_asbd) != noErr) { | |
429 return false; | |
430 } | |
431 | |
432 if (AudioConverterNew(&in_asbd, &out_asbd, &converter_) != noErr) { | |
433 return false; | |
434 } | |
435 | |
436 // The converter is allowed to modify (really fill-in) the output format. | |
437 // After creation, we can query the final output format. | |
438 prop_size = sizeof(out_asbd); | |
439 if (AudioConverterGetProperty(converter_, | |
440 kAudioConverterCurrentOutputStreamDescription, | |
441 &prop_size, | |
442 &out_asbd) != noErr) { | |
443 return false; | |
444 } | |
445 | |
446 // If bitrate is <= 0, allow the encoder to pick a suitable value. | |
447 // Otherwise, set the bitrate (which can fail if the value is not suitable | |
448 // or compatible with the output sampling rate or channels). | |
449 if (bitrate > 0) { | |
450 prop_size = sizeof(int); | |
451 if (AudioConverterSetProperty( | |
452 converter_, kAudioConverterEncodeBitRate, prop_size, &bitrate) != | |
453 noErr) { | |
454 return false; | |
455 } | |
456 } | |
457 | |
458 // See the comment next to |can_resume_| for details on resumption. Some | |
459 // converters can return kAudioConverterErr_PropertyNotSupported, in which | |
460 // case resumption is implicitly supported. | |
461 uint32_t can_resume; | |
462 prop_size = sizeof(can_resume); | |
463 OSStatus oserr = AudioConverterGetProperty( | |
464 converter_, | |
465 kAudioConverterPropertyCanResumeFromInterruption, | |
466 &prop_size, | |
467 &can_resume); | |
468 if (oserr == noErr) { | |
469 const_cast<bool&>(can_resume_) = can_resume != 0; | |
470 } | |
471 | |
472 // mBytesPerPacket will be 0 for variable packet size configurations, in | |
473 // which case we must query the maximum possible packet size. | |
474 const_cast<uint32_t&>(max_packet_size_) = out_asbd.mBytesPerPacket; | |
475 if (max_packet_size_ == 0) { | |
476 prop_size = sizeof(max_packet_size_); | |
477 if (AudioConverterGetProperty( | |
478 converter_, | |
479 kAudioConverterPropertyMaximumOutputPacketSize, | |
480 &prop_size, | |
481 const_cast<uint32_t*>(&max_packet_size_)) != noErr) { | |
482 return false; | |
483 } | |
484 } | |
485 | |
486 // This is the only location where we modify the packet buffer. | |
487 const_cast<scoped_ptr<uint8[]>&>(packet_buffer_) | |
488 .reset(new uint8[max_packet_size_]); | |
489 | |
490 // The "magic cookie" is an encoder state vector required for decoding and | |
491 // packing. We query it from the converter and set it on the file below. | |
492 UInt32 cookie_size; | |
493 if (AudioConverterGetPropertyInfo(converter_, | |
494 kAudioConverterCompressionMagicCookie, | |
495 &cookie_size, | |
496 nullptr) != noErr) { | |
497 return false; | |
498 } | |
499 scoped_ptr<int8[]> cookie_data(new int8[cookie_size]); | |
miu
2014/09/29 19:54:47
Sanity-check: Did you mean uint8 here, or is int8
jfroy
2014/10/14 01:06:34
Their API use void*, which doesn't play well in C+
| |
500 if (AudioConverterGetProperty(converter_, | |
501 kAudioConverterCompressionMagicCookie, | |
502 &cookie_size, | |
503 cookie_data.get()) != noErr) { | |
504 return false; | |
505 } | |
506 | |
507 if (AudioFileInitializeWithCallbacks(this, | |
508 nullptr, | |
509 &FileWriteCallback, | |
510 nullptr, | |
511 nullptr, | |
512 kAudioFileAAC_ADTSType, | |
513 &out_asbd, | |
514 0, | |
515 &file_) != noErr) { | |
516 return false; | |
517 } | |
518 | |
519 if (AudioFileSetProperty(file_, | |
520 kAudioFilePropertyMagicCookieData, | |
521 cookie_size, | |
522 cookie_data.get()) != noErr) { | |
523 return false; | |
524 } | |
525 | |
526 return true; | |
527 } | |
528 | |
529 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus, | |
530 int source_offset, | |
531 int buffer_fill_offset, | |
532 int num_samples) override { | |
533 audio_bus->CopyPartialFramesTo( | |
534 source_offset, num_samples, buffer_fill_offset, input_buffer_.get()); | |
535 } | |
536 | |
537 virtual bool EncodeFromFilledBuffer(std::string* out) override { | |
538 AudioBufferList out_abl; | |
miu
2014/09/29 19:54:47
nit: Can out_abl be initialized once in Initialize
jfroy
2014/10/14 01:06:34
Good idea.
| |
539 out_abl.mNumberBuffers = 1; | |
540 out_abl.mBuffers[0].mNumberChannels = num_channels_; | |
541 out_abl.mBuffers[0].mDataByteSize = max_packet_size_; | |
542 out_abl.mBuffers[0].mData = packet_buffer_.get(); | |
543 | |
544 UInt32 io_num_packets = 1; | |
545 AudioStreamPacketDescription packet_description; | |
546 if (AudioConverterFillComplexBuffer(converter_, | |
547 &ConverterFillDataCallback, | |
548 this, | |
549 &io_num_packets, | |
550 &out_abl, | |
551 &packet_description) != noErr || | |
552 io_num_packets == 0) { | |
553 return false; | |
554 } | |
555 | |
556 // Reserve enough space to write the packet and a basic ADTS header. | |
557 out->reserve(packet_description.mDataByteSize + 7); | |
miu
2014/09/29 19:54:47
Where does 7 come from? Can you specify this as s
jfroy
2014/10/14 01:06:34
It's the ADTS header size. I've switched to a cons
| |
558 | |
559 output_buffer_ = out; | |
560 OSStatus oserr = AudioFileWritePackets(file_, | |
561 false, | |
562 out_abl.mBuffers[0].mDataByteSize, | |
563 &packet_description, | |
564 num_encoded_packets_, | |
565 &io_num_packets, | |
566 out_abl.mBuffers[0].mData); | |
567 output_buffer_ = nullptr; | |
568 if (oserr != noErr || io_num_packets == 0) { | |
569 return false; | |
570 } | |
571 num_encoded_packets_ += io_num_packets; | |
572 return true; | |
573 } | |
574 | |
575 // A buffer that holds one encoded packet worth of audio frames. Initialized | |
576 // during construction. | |
577 const scoped_ptr<AudioBus> input_buffer_; | |
578 | |
579 // A buffer that holds one encoded packet. Initialized in |Initialize| once | |
580 // the maximum packet size is known. | |
581 const scoped_ptr<uint8[]> packet_buffer_; | |
582 | |
583 // A temporary pointer to the current output buffer. Only non-null when | |
584 // writing a packet for use by the AudioFile write callback. | |
585 std::string* output_buffer_; | |
586 | |
587 // The AudioConverter is responsible for encoding LPCM frames to AAC packets. | |
588 AudioConverterRef converter_; | |
589 | |
590 // The AudioFile is responsible for wrapping AAC packets into ADTS packets. | |
591 AudioFileID file_; | |
592 | |
593 // The number of encoded packets emitted so far by the encoder. | |
594 uint64_t num_encoded_packets_; | |
595 | |
596 // The maximum packet size that the encoder can emit. | |
597 const uint32_t max_packet_size_; | |
598 | |
599 // On iOS, AudioConverter can be interrupted by other services (such as an | |
600 // audio alert or phone call). Depending on the underlying hardware and | |
601 // configuration, the converter may have to be thrown away and re-initialized | |
602 // after such an interruption. This flag tracks if we can resume or not. | |
603 const bool can_resume_; | |
miu
2014/09/29 19:54:47
Is this used anywhere?
jfroy
2014/10/14 01:06:34
Not yet but I'll be filing a bug to add support fo
| |
604 | |
605 DISALLOW_COPY_AND_ASSIGN(AacAudioConverterImpl); | |
606 }; | |
607 #endif // defined(OS_MACOSX) | |
293 | 608 |
294 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase { | 609 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase { |
295 public: | 610 public: |
296 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, | 611 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, |
297 int num_channels, | 612 int num_channels, |
298 int sampling_rate, | 613 int sampling_rate, |
299 const FrameEncodedCallback& callback) | 614 const FrameEncodedCallback& callback) |
300 : ImplBase(cast_environment, | 615 : ImplBase(cast_environment, |
301 CODEC_AUDIO_PCM16, | 616 CODEC_AUDIO_PCM16, |
302 num_channels, | 617 num_channels, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
345 int num_channels, | 660 int num_channels, |
346 int sampling_rate, | 661 int sampling_rate, |
347 int bitrate, | 662 int bitrate, |
348 Codec codec, | 663 Codec codec, |
349 const FrameEncodedCallback& frame_encoded_callback) | 664 const FrameEncodedCallback& frame_encoded_callback) |
350 : cast_environment_(cast_environment) { | 665 : cast_environment_(cast_environment) { |
351 // Note: It doesn't matter which thread constructs AudioEncoder, just so long | 666 // Note: It doesn't matter which thread constructs AudioEncoder, just so long |
352 // as all calls to InsertAudio() are by the same thread. | 667 // as all calls to InsertAudio() are by the same thread. |
353 insert_thread_checker_.DetachFromThread(); | 668 insert_thread_checker_.DetachFromThread(); |
354 switch (codec) { | 669 switch (codec) { |
670 #if !defined(OS_IOS) | |
355 case CODEC_AUDIO_OPUS: | 671 case CODEC_AUDIO_OPUS: |
356 impl_ = new OpusImpl(cast_environment, | 672 impl_ = new OpusImpl(cast_environment, |
357 num_channels, | 673 num_channels, |
358 sampling_rate, | 674 sampling_rate, |
359 bitrate, | 675 bitrate, |
360 frame_encoded_callback); | 676 frame_encoded_callback); |
361 break; | 677 break; |
678 #endif | |
679 #if defined(OS_MACOSX) | |
680 case CODEC_AUDIO_AAC: | |
681 impl_ = new AacAudioConverterImpl(cast_environment, | |
682 num_channels, | |
683 sampling_rate, | |
684 bitrate, | |
685 frame_encoded_callback); | |
686 break; | |
687 #endif // defined(OS_MACOSX) | |
362 case CODEC_AUDIO_PCM16: | 688 case CODEC_AUDIO_PCM16: |
363 impl_ = new Pcm16Impl(cast_environment, | 689 impl_ = new Pcm16Impl(cast_environment, |
364 num_channels, | 690 num_channels, |
365 sampling_rate, | 691 sampling_rate, |
366 frame_encoded_callback); | 692 frame_encoded_callback); |
367 break; | 693 break; |
368 default: | 694 default: |
369 NOTREACHED() << "Unsupported or unspecified codec for audio encoder"; | 695 NOTREACHED() << "Unsupported or unspecified codec for audio encoder"; |
370 break; | 696 break; |
371 } | 697 } |
(...skipping 29 matching lines...) Expand all Loading... | |
401 cast_environment_->PostTask(CastEnvironment::AUDIO, | 727 cast_environment_->PostTask(CastEnvironment::AUDIO, |
402 FROM_HERE, | 728 FROM_HERE, |
403 base::Bind(&AudioEncoder::ImplBase::EncodeAudio, | 729 base::Bind(&AudioEncoder::ImplBase::EncodeAudio, |
404 impl_, | 730 impl_, |
405 base::Passed(&audio_bus), | 731 base::Passed(&audio_bus), |
406 recorded_time)); | 732 recorded_time)); |
407 } | 733 } |
408 | 734 |
409 } // namespace cast | 735 } // namespace cast |
410 } // namespace media | 736 } // namespace media |
OLD | NEW |