Skip to content

Commit

Permalink
[media] Create AudioDiscardDurationTracker
Browse files Browse the repository at this point in the history
1. Creates a class AudioDiscardDurationTracker to store the discard
   durations of audio buffers sent to pass-through audio renderers. The
   stored durations can then be used during media time calculation. This
   is implemented for the Android pass-through audio renderer.

   b/313719729
  • Loading branch information
osagie98 committed Nov 29, 2023
1 parent c905013 commit 900559f
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 3 deletions.
9 changes: 9 additions & 0 deletions starboard/android/shared/audio_renderer_passthrough.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ void AudioRendererPassthrough::WriteSamples(const InputBuffers& input_buffers) {
decoder_->Decode(
input_buffers,
std::bind(&AudioRendererPassthrough::OnDecoderConsumed, this));

discard_duration_tracker_.CacheMultipleDiscardDurations(input_buffers);
}

void AudioRendererPassthrough::WriteEndOfStream() {
Expand Down Expand Up @@ -289,6 +291,7 @@ void AudioRendererPassthrough::Seek(SbTime seek_to_time) {
decoded_audio_writing_in_progress_ = nullptr;
decoded_audio_writing_offset_ = 0;
total_frames_written_on_audio_track_thread_ = 0;
discard_duration_tracker_.Reset();
}

// This function can be called from *any* threads.
Expand Down Expand Up @@ -334,6 +337,8 @@ SbTime AudioRendererPassthrough::GetCurrentMediaTime(bool* is_playing,
playback_time =
audio_start_time + total_frames_played * kSbTimeSecond /
audio_stream_info_.samples_per_second;
playback_time = discard_duration_tracker_.AdjustTimeForTotalDiscardDuration(
playback_time);
return std::max(playback_time, seek_to_time_);
}

Expand All @@ -350,6 +355,8 @@ SbTime AudioRendererPassthrough::GetCurrentMediaTime(bool* is_playing,
// returned on pause, after an adjusted time has been returned.
playback_time = audio_start_time + playback_head_position * kSbTimeSecond /
audio_stream_info_.samples_per_second;
playback_time = discard_duration_tracker_.AdjustTimeForTotalDiscardDuration(
playback_time);

// When underlying AudioTrack is paused, we use returned playback time
// directly. Note that we should not use |paused_| or |playback_rate_| here.
Expand Down Expand Up @@ -558,6 +565,8 @@ void AudioRendererPassthrough::UpdateStatusAndWriteData(
if (decoded_audio_writing_offset_ ==
decoded_audio_writing_in_progress_->size_in_bytes()) {
total_frames_written_on_audio_track_thread_ += frames_per_input_buffer_;
discard_duration_tracker_.AddCachedDiscardDurationToTotal(
decoded_audio_writing_in_progress_->timestamp());
decoded_audio_writing_in_progress_ = nullptr;
decoded_audio_writing_offset_ = 0;
fully_written = true;
Expand Down
5 changes: 5 additions & 0 deletions starboard/android/shared/audio_renderer_passthrough.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "starboard/shared/internal_only.h"
#include "starboard/shared/starboard/media/media_util.h"
#include "starboard/shared/starboard/player/decoded_audio_internal.h"
#include "starboard/shared/starboard/player/filter/audio_discard_duration_tracker.h"
#include "starboard/shared/starboard/player/filter/audio_renderer_internal.h"
#include "starboard/shared/starboard/player/filter/common.h"
#include "starboard/shared/starboard/player/filter/media_time_provider.h"
Expand All @@ -52,6 +53,8 @@ class AudioRendererPassthrough
public:
typedef ::starboard::shared::starboard::media::AudioStreamInfo
AudioStreamInfo;
typedef ::starboard::shared::starboard::player::filter::
AudioDiscardDurationTracker AudioDiscardDurationTracker;

AudioRendererPassthrough(const AudioStreamInfo& audio_stream_info,
SbDrmSystem drm_system);
Expand Down Expand Up @@ -148,6 +151,8 @@ class AudioRendererPassthrough
// invalidated.
std::unique_ptr<AudioTrackBridge> audio_track_bridge_;
std::unique_ptr<JobThread> audio_track_thread_;

AudioDiscardDurationTracker discard_duration_tracker_;
};

} // namespace shared
Expand Down
2 changes: 2 additions & 0 deletions starboard/shared/starboard/player/decoded_audio_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ void DecodedAudio::AdjustForDiscardedDurations(
? current_frames
: AudioDurationToFrames(discarded_duration_from_back, sample_rate);
size_in_bytes_ -= bytes_per_frame * discarded_frames_from_back;
total_discarded_duration_ +=
discarded_duration_from_front + discarded_duration_from_back;
}

scoped_refptr<DecodedAudio> DecodedAudio::SwitchFormatTo(
Expand Down
3 changes: 3 additions & 0 deletions starboard/shared/starboard/player/decoded_audio_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class DecodedAudio : public RefCountedThreadSafe<DecodedAudio> {
return reinterpret_cast<float*>(storage_.data() + offset_in_bytes_);
}
int frames() const;
SbTime total_discarded_duration() const { return total_discarded_duration_; }

void ShrinkTo(int new_size_in_bytes);

Expand Down Expand Up @@ -109,6 +110,8 @@ class DecodedAudio : public RefCountedThreadSafe<DecodedAudio> {
int offset_in_bytes_ = 0;
int size_in_bytes_ = 0;

SbTime total_discarded_duration_ = 0;

DecodedAudio(const DecodedAudio&) = delete;
void operator=(const DecodedAudio&) = delete;
};
Expand Down
2 changes: 2 additions & 0 deletions starboard/shared/starboard/player/filter/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ static_library("filter_based_player_sources") {
"//starboard/shared/starboard/player/filter/audio_channel_layout_mixer.h",
"//starboard/shared/starboard/player/filter/audio_channel_layout_mixer_impl.cc",
"//starboard/shared/starboard/player/filter/audio_decoder_internal.h",
"//starboard/shared/starboard/player/filter/audio_discard_duration_tracker.cc",
"//starboard/shared/starboard/player/filter/audio_discard_duration_tracker.h",
"//starboard/shared/starboard/player/filter/audio_frame_discarder.cc",
"//starboard/shared/starboard/player/filter/audio_frame_discarder.h",
"//starboard/shared/starboard/player/filter/audio_frame_tracker.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "starboard/shared/starboard/player/filter/audio_discard_duration_tracker.h"

#include <algorithm>
#include <unordered_map>

#include "starboard/common/log.h"
#include "starboard/media.h"
#include "starboard/shared/starboard/media/media_util.h"

namespace starboard {
namespace shared {
namespace starboard {
namespace player {
namespace filter {
using shared::starboard::media::AudioSampleInfo;

void AudioDiscardDurationTracker::CacheDiscardDuration(
const InputBuffer& input_buffer) {
SB_DCHECK(input_buffer.sample_type() == kSbMediaTypeAudio);
const AudioSampleInfo audio_sample_info = input_buffer.audio_sample_info();
discard_durations_by_timestamp_[input_buffer.timestamp()] =
audio_sample_info.discarded_duration_from_front +
audio_sample_info.discarded_duration_from_back;
}

void AudioDiscardDurationTracker::CacheMultipleDiscardDurations(
const InputBuffers& input_buffers) {
for (const auto& input_buffer : input_buffers) {
CacheDiscardDuration(*input_buffer.get());
}
}

void AudioDiscardDurationTracker::AddCachedDiscardDurationToTotal(
SbTime timestamp,
bool remove_timestamp_from_cache) {
if (discard_durations_by_timestamp_.find(timestamp) ==
discard_durations_by_timestamp_.end()) {
SB_LOG(INFO) << "Discarded duration for timestamp: " << timestamp
<< " is not cached.";
return;
}

if (discard_durations_by_timestamp_.find(timestamp) !=
discard_durations_by_timestamp_.end()) {
total_discard_duration_ += discard_durations_by_timestamp_[timestamp];
if (remove_timestamp_from_cache) {
discard_durations_by_timestamp_.erase(timestamp);
}
}
}

SbTime AudioDiscardDurationTracker::AdjustTimeForTotalDiscardDuration(
SbTime timestamp) {
SbTime adjusted_timestamp = timestamp - total_discard_duration_;
return std::max(SbTime(0), adjusted_timestamp);
}

} // namespace filter
} // namespace player
} // namespace starboard
} // namespace shared
} // namespace starboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_AUDIO_DISCARD_DURATION_TRACKER_H_
#define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_AUDIO_DISCARD_DURATION_TRACKER_H_

#include <unordered_map>

#include "starboard/shared/internal_only.h"
#include "starboard/shared/starboard/player/input_buffer_internal.h"
#include "starboard/time.h"

namespace starboard {
namespace shared {
namespace starboard {
namespace player {
namespace filter {

// This class caches the discard durations of audio buffers to maintain a
// running total discard duration. This total can be used to adjust the media
// time of the playback when the audio buffers do not support partial audio,
// and prevent an A/V desync.
class AudioDiscardDurationTracker {
public:
void CacheDiscardDuration(const InputBuffer& input_buffer);
void CacheMultipleDiscardDurations(const InputBuffers& input_buffers);
void AddCachedDiscardDurationToTotal(SbTime timestamp,
bool remove_timestamp_from_cache = true);
SbTime AdjustTimeForTotalDiscardDuration(SbTime timestamp);
void Reset() {
discard_durations_by_timestamp_.clear();
total_discard_duration_ = 0;
}

SbTime total_discard_duration() const { return total_discard_duration_; }

private:
std::unordered_map<SbTime, SbTime> discard_durations_by_timestamp_;
SbTime total_discard_duration_ = 0;
};

} // namespace filter
} // namespace player
} // namespace starboard
} // namespace shared
} // namespace starboard

#endif // STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_AUDIO_DISCARD_DURATION_TRACKER_H_
13 changes: 10 additions & 3 deletions starboard/shared/uwp/audio_renderer_passthrough.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ void AudioRendererPassthrough::WriteSamples(const InputBuffers& input_buffers) {
decoder_->Decode(
input_buffers,
std::bind(&AudioRendererPassthrough::OnDecoderConsumed, this));
discard_duration_tracker_.CacheMultipleDiscardDurations(input_buffers);
}

void AudioRendererPassthrough::WriteEndOfStream() {
Expand Down Expand Up @@ -179,6 +180,8 @@ void AudioRendererPassthrough::Seek(SbTime seek_to_time) {
ScopedLock lock(mutex_);
seeking_to_time_ = std::max<SbTime>(seek_to_time, 0);
seeking_ = true;
first_written_timestamp_ = -1;
discard_duration_tracker_.Reset();
}

total_frames_sent_to_sink_ = 0;
Expand Down Expand Up @@ -226,11 +229,12 @@ SbTime AudioRendererPassthrough::GetCurrentMediaTime(bool* is_playing,

SbTime media_time = seeking_to_time_ + sink_playback_time;
if (!sink_->playing()) {
return media_time;
return discard_duration_tracker_.AdjustTimeForTotalDiscardDuration(
media_time);
}

return media_time +
CalculateElapsedPlaybackTime(sink_playback_time_updated_at);
return discard_duration_tracker_.AdjustTimeForTotalDiscardDuration(
media_time + CalculateElapsedPlaybackTime(sink_playback_time_updated_at));
}

void AudioRendererPassthrough::OnDecoderConsumed() {
Expand Down Expand Up @@ -284,6 +288,9 @@ void AudioRendererPassthrough::ProcessAudioBuffers() {
if (decoded_audio && TryToWriteAudioBufferToSink(decoded_audio)) {
pending_inputs_.pop();
process_audio_buffers_job_delay = 0;
if (first_written_timestamp_ < 0) {
first_written_timestamp_ = decoded_audio->timestamp();
}
if (seeking_ && total_buffers_sent_to_sink_ >= kNumPrerollDecodedAudios) {
seeking_ = false;
Schedule(prerolled_cb_);
Expand Down
8 changes: 8 additions & 0 deletions starboard/shared/uwp/audio_renderer_passthrough.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "starboard/shared/starboard/media/media_util.h"
#include "starboard/shared/starboard/player/decoded_audio_internal.h"
#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
#include "starboard/shared/starboard/player/filter/audio_discard_duration_tracker.h"
#include "starboard/shared/starboard/player/filter/audio_renderer_internal.h"
#include "starboard/shared/starboard/player/filter/media_time_provider.h"
#include "starboard/shared/starboard/player/input_buffer_internal.h"
Expand All @@ -41,6 +42,8 @@ namespace uwp {
using ::starboard::shared::starboard::player::DecodedAudio;
using ::starboard::shared::starboard::player::JobQueue;
using ::starboard::shared::starboard::player::filter::AudioDecoder;
using ::starboard::shared::starboard::player::filter::
AudioDiscardDurationTracker;
using ::starboard::shared::starboard::player::filter::AudioRenderer;
using ::starboard::shared::starboard::player::filter::MediaTimeProvider;

Expand Down Expand Up @@ -106,6 +109,9 @@ class AudioRendererPassthrough : public AudioRenderer,
bool seeking_ = false;
double playback_rate_ = 1.0;
SbTime seeking_to_time_ = 0;
// Used to adjust the media time when the timestamp of the first written
// buffer doesn't align to |seeking_to_time_|.
SbTime first_written_timestamp_ = -1;

atomic_bool end_of_stream_written_{false};
atomic_bool end_of_stream_played_{false};
Expand All @@ -131,6 +137,8 @@ class AudioRendererPassthrough : public AudioRenderer,

// Used to calculate the media time in GetCurrentMediaTime().
LARGE_INTEGER performance_frequency_;

AudioDiscardDurationTracker discard_duration_tracker_;
};

} // namespace uwp
Expand Down

0 comments on commit 900559f

Please sign in to comment.