summaryrefslogtreecommitdiff
path: root/media/cast/audio_receiver/audio_decoder.cc
blob: 118a020b30c32053121beb0df82f5737a4ce3f45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 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.

#include "base/logging.h"
#include "media/cast/audio_receiver/audio_decoder.h"

#include "third_party/webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
#include "third_party/webrtc/modules/interface/module_common_types.h"

namespace media {
namespace cast {

AudioDecoder::AudioDecoder(const AudioReceiverConfig& audio_config)
    : audio_decoder_(webrtc::AudioCodingModule::Create(0)),
      have_received_packets_(false) {
  audio_decoder_->InitializeReceiver();

  webrtc::CodecInst receive_codec;
  switch (audio_config.codec) {
    case kPcm16:
      receive_codec.pltype = audio_config.rtp_payload_type;
      strncpy(receive_codec.plname, "L16", 4);
      receive_codec.plfreq = audio_config.frequency;
      receive_codec.pacsize = -1;
      receive_codec.channels = audio_config.channels;
      receive_codec.rate = -1;
      break;
    case kOpus:
      receive_codec.pltype = audio_config.rtp_payload_type;
      strncpy(receive_codec.plname, "opus", 5);
      receive_codec.plfreq = audio_config.frequency;
      receive_codec.pacsize = -1;
      receive_codec.channels = audio_config.channels;
      receive_codec.rate = -1;
      break;
    case kExternalAudio:
      DCHECK(false) << "Codec must be specified for audio decoder";
      break;
  }
  if (audio_decoder_->RegisterReceiveCodec(receive_codec) != 0) {
    DCHECK(false) << "Failed to register receive codec";
  }

  audio_decoder_->SetMaximumPlayoutDelay(audio_config.rtp_max_delay_ms);
  audio_decoder_->SetPlayoutMode(webrtc::streaming);
}

AudioDecoder::~AudioDecoder() {}

bool AudioDecoder::GetRawAudioFrame(int number_of_10ms_blocks,
                                    int desired_frequency,
                                    PcmAudioFrame* audio_frame,
                                    uint32* rtp_timestamp) {
  // We don't care about the race case where a packet arrives at the same time
  // as this function in called. The data will be there the next time this
  // function is called.
  lock_.Acquire();
  // Get a local copy under lock.
  bool have_received_packets = have_received_packets_;
  lock_.Release();

  if (!have_received_packets) return false;

  audio_frame->samples.clear();

  for (int i = 0; i < number_of_10ms_blocks; ++i) {
    webrtc::AudioFrame webrtc_audio_frame;
    if (0 != audio_decoder_->PlayoutData10Ms(desired_frequency,
                                             &webrtc_audio_frame)) {
      return false;
    }
    if (webrtc_audio_frame.speech_type_ == webrtc::AudioFrame::kPLCCNG ||
        webrtc_audio_frame.speech_type_ == webrtc::AudioFrame::kUndefined) {
      // We are only interested in real decoded audio.
      return false;
    }
    audio_frame->frequency = webrtc_audio_frame.sample_rate_hz_;
    audio_frame->channels = webrtc_audio_frame.num_channels_;

    if (i == 0) {
      // Use the timestamp from the first 10ms block.
      if (0 != audio_decoder_->PlayoutTimestamp(rtp_timestamp)) {
        return false;
      }
    }
    int samples_per_10ms = webrtc_audio_frame.samples_per_channel_;

    audio_frame->samples.insert(
        audio_frame->samples.end(),
        &webrtc_audio_frame.data_[0],
        &webrtc_audio_frame.data_[samples_per_10ms * audio_frame->channels]);
  }
  return true;
}

void AudioDecoder::IncomingParsedRtpPacket(const uint8* payload_data,
                                           size_t payload_size,
                                           const RtpCastHeader& rtp_header) {
  DCHECK_LE(payload_size, kIpPacketSize);
  audio_decoder_->IncomingPacket(payload_data, static_cast<int32>(payload_size),
                                 rtp_header.webrtc);

  lock_.Acquire();
  have_received_packets_ = true;
  lock_.Release();
}

}  // namespace cast
}  // namespace media