OLD | NEW |
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 package org.chromium.media; | 5 package org.chromium.media; |
6 | 6 |
7 import android.media.AudioFormat; | 7 import android.media.AudioFormat; |
8 import android.media.AudioManager; | 8 import android.media.AudioManager; |
9 import android.media.AudioTrack; | 9 import android.media.AudioTrack; |
10 import android.media.MediaCodec; | 10 import android.media.MediaCodec; |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 Log.e(TAG, "Failed to dequeue input buffer", e); | 273 Log.e(TAG, "Failed to dequeue input buffer", e); |
274 } | 274 } |
275 return new DequeueInputResult(status, index); | 275 return new DequeueInputResult(status, index); |
276 } | 276 } |
277 | 277 |
278 @CalledByNative | 278 @CalledByNative |
279 private int flush() { | 279 private int flush() { |
280 try { | 280 try { |
281 mFlushed = true; | 281 mFlushed = true; |
282 if (mAudioTrack != null) { | 282 if (mAudioTrack != null) { |
| 283 // Need to call pause() here, or otherwise flush() is a no-op. |
| 284 mAudioTrack.pause(); |
283 mAudioTrack.flush(); | 285 mAudioTrack.flush(); |
284 } | 286 } |
285 mMediaCodec.flush(); | 287 mMediaCodec.flush(); |
286 } catch (IllegalStateException e) { | 288 } catch (IllegalStateException e) { |
287 Log.e(TAG, "Failed to flush MediaCodec", e); | 289 Log.e(TAG, "Failed to flush MediaCodec", e); |
288 return MEDIA_CODEC_ERROR; | 290 return MEDIA_CODEC_ERROR; |
289 } | 291 } |
290 return MEDIA_CODEC_OK; | 292 return MEDIA_CODEC_OK; |
291 } | 293 } |
292 | 294 |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 return false; | 515 return false; |
514 } | 516 } |
515 } | 517 } |
516 return true; | 518 return true; |
517 } catch (IllegalStateException e) { | 519 } catch (IllegalStateException e) { |
518 Log.e(TAG, "Cannot configure the audio codec", e); | 520 Log.e(TAG, "Cannot configure the audio codec", e); |
519 } | 521 } |
520 return false; | 522 return false; |
521 } | 523 } |
522 | 524 |
| 525 /** |
| 526 * Play the audio buffer that is passed in. |
| 527 * |
| 528 * @param buf Audio buffer to be rendered. |
| 529 * @return The number of frames that have already been consumed by the |
| 530 * hardware. This number resets to 0 after each flush call. |
| 531 */ |
523 @CalledByNative | 532 @CalledByNative |
524 private void playOutputBuffer(byte[] buf) { | 533 private long playOutputBuffer(byte[] buf) { |
525 if (mAudioTrack != null) { | 534 if (mAudioTrack != null) { |
526 if (AudioTrack.PLAYSTATE_PLAYING != mAudioTrack.getPlayState()) { | 535 if (AudioTrack.PLAYSTATE_PLAYING != mAudioTrack.getPlayState()) { |
527 mAudioTrack.play(); | 536 mAudioTrack.play(); |
528 } | 537 } |
529 int size = mAudioTrack.write(buf, 0, buf.length); | 538 int size = mAudioTrack.write(buf, 0, buf.length); |
530 if (buf.length != size) { | 539 if (buf.length != size) { |
531 Log.i(TAG, "Failed to send all data to audio output, expected si
ze: " + | 540 Log.i(TAG, "Failed to send all data to audio output, expected si
ze: " + |
532 buf.length + ", actual size: " + size); | 541 buf.length + ", actual size: " + size); |
533 } | 542 } |
| 543 // TODO(qinmin): Returning the head position allows us to estimate |
| 544 // the current presentation time in native code. However, it is |
| 545 // better to use AudioTrack.getCurrentTimestamp() to get the last |
| 546 // known time when a frame is played. However, we will need to |
| 547 // convert the java nano time to C++ timestamp. |
| 548 // If the stream runs too long, getPlaybackHeadPosition() could |
| 549 // overflow. AudioTimestampHelper in MediaSourcePlayer has the same |
| 550 // issue. See http://crbug.com/358801. |
| 551 return mAudioTrack.getPlaybackHeadPosition(); |
534 } | 552 } |
| 553 return 0; |
535 } | 554 } |
536 | 555 |
537 @CalledByNative | 556 @CalledByNative |
538 private void setVolume(double volume) { | 557 private void setVolume(double volume) { |
539 if (mAudioTrack != null) { | 558 if (mAudioTrack != null) { |
540 mAudioTrack.setStereoVolume((float) volume, (float) volume); | 559 mAudioTrack.setStereoVolume((float) volume, (float) volume); |
541 } | 560 } |
542 } | 561 } |
543 | 562 |
544 private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) { | 563 private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) { |
(...skipping 14 matching lines...) Expand all Loading... |
559 return AudioFormat.CHANNEL_OUT_QUAD; | 578 return AudioFormat.CHANNEL_OUT_QUAD; |
560 case 6: | 579 case 6: |
561 return AudioFormat.CHANNEL_OUT_5POINT1; | 580 return AudioFormat.CHANNEL_OUT_5POINT1; |
562 case 8: | 581 case 8: |
563 return AudioFormat.CHANNEL_OUT_7POINT1; | 582 return AudioFormat.CHANNEL_OUT_7POINT1; |
564 default: | 583 default: |
565 return AudioFormat.CHANNEL_OUT_DEFAULT; | 584 return AudioFormat.CHANNEL_OUT_DEFAULT; |
566 } | 585 } |
567 } | 586 } |
568 } | 587 } |
OLD | NEW |