// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_CAST_AUDIO_RECEIVER_AUDIO_RECEIVER_H_
#define MEDIA_CAST_AUDIO_RECEIVER_AUDIO_RECEIVER_H_

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "media/cast/cast_config.h"
#include "media/cast/cast_environment.h"
#include "media/cast/cast_receiver.h"
#include "media/cast/rtcp/rtcp.h"  // RtcpCastMessage
#include "media/cast/rtp_receiver/rtp_receiver_defines.h"  // RtpCastHeader

namespace crypto {
  class Encryptor;
}

namespace media {
namespace cast {

class AudioDecoder;
class Framer;
class LocalRtpAudioData;
class LocalRtpAudioFeedback;
class PacedPacketSender;
class RtpReceiver;
class RtpReceiverStatistics;

struct DecodedAudioCallbackData {
  DecodedAudioCallbackData();
  ~DecodedAudioCallbackData();
  int number_of_10ms_blocks;
  int desired_frequency;
  AudioFrameDecodedCallback callback;
};

// This class is not thread safe. Should only be called from the Main cast
// thread.
class AudioReceiver : public base::NonThreadSafe,
                      public base::SupportsWeakPtr<AudioReceiver> {
 public:
  AudioReceiver(scoped_refptr<CastEnvironment> cast_environment,
                const AudioReceiverConfig& audio_config,
                PacedPacketSender* const packet_sender);

  virtual ~AudioReceiver();

  // Extract a raw audio frame from the cast receiver.
  // Actual decoding will be preformed on a designated audio_decoder thread.
  void GetRawAudioFrame(int number_of_10ms_blocks,
                        int desired_frequency,
                        const AudioFrameDecodedCallback& callback);

  // Extract an encoded audio frame from the cast receiver.
  void GetEncodedAudioFrame(const AudioFrameEncodedCallback& callback);

  // Should only be called from the main cast thread.
  void IncomingPacket(const uint8* packet, size_t length,
                      const base::Closure callback);

 protected:
  void IncomingParsedRtpPacket(const uint8* payload_data,
                               size_t payload_size,
                               const RtpCastHeader& rtp_header);
 private:
  friend class LocalRtpAudioData;
  friend class LocalRtpAudioFeedback;

  void CastFeedback(const RtcpCastMessage& cast_message);

  // Time to pull out the audio even though we are missing data.
  void PlayoutTimeout();

  bool PostEncodedAudioFrame(const AudioFrameEncodedCallback& callback,
                             uint32 rtp_timestamp,
                             bool next_frame,
                             scoped_ptr<EncodedAudioFrame>* encoded_frame);

  // Actual decoding implementation - should be called under the audio decoder
  // thread.
  void DecodeAudioFrameThread(int number_of_10ms_blocks,
                              int desired_frequency,
                              const AudioFrameDecodedCallback callback);
  void ReturnDecodedFrameWithPlayoutDelay(
      scoped_ptr<PcmAudioFrame> audio_frame, uint32 rtp_timestamp,
      const AudioFrameDecodedCallback callback);

  // Return the playout time based on the current time and rtp timestamp.
  base::TimeTicks GetPlayoutTime(base::TimeTicks now, uint32 rtp_timestamp);

  void InitializeTimers();

  // Decrypts the data within the |audio_frame| and replaces the data with the
  // decrypted string.
  bool DecryptAudioFrame(scoped_ptr<EncodedAudioFrame>* audio_frame);

  // Schedule the next RTCP report.
  void ScheduleNextRtcpReport();

  // Actually send the next RTCP report.
  void SendNextRtcpReport();

  // Schedule timing for the next cast message.
  void ScheduleNextCastMessage();

  // Actually send the next cast message.
  void SendNextCastMessage();

  scoped_refptr<CastEnvironment> cast_environment_;
  base::WeakPtrFactory<AudioReceiver> weak_factory_;

  const AudioCodec codec_;
  const int frequency_;
  base::TimeDelta target_delay_delta_;
  scoped_ptr<Framer> audio_buffer_;
  scoped_ptr<AudioDecoder> audio_decoder_;
  scoped_ptr<LocalRtpAudioData> incoming_payload_callback_;
  scoped_ptr<LocalRtpAudioFeedback> incoming_payload_feedback_;
  scoped_ptr<RtpReceiver> rtp_receiver_;
  scoped_ptr<Rtcp> rtcp_;
  scoped_ptr<RtpReceiverStatistics> rtp_audio_receiver_statistics_;
  base::TimeDelta time_offset_;
  base::TimeTicks time_first_incoming_packet_;
  uint32 first_incoming_rtp_timestamp_;
  scoped_ptr<crypto::Encryptor> decryptor_;
  std::string iv_mask_;

  std::list<AudioFrameEncodedCallback> queued_encoded_callbacks_;
  std::list<DecodedAudioCallbackData> queued_decoded_callbacks_;
};

}  // namespace cast
}  // namespace media

#endif  // MEDIA_CAST_AUDIO_RECEIVER_AUDIO_RECEIVER_H_