1/*
2 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/base/transformadapter.h"
12
13#include <string.h>
14
15#include "webrtc/base/common.h"
16
17namespace rtc {
18
19///////////////////////////////////////////////////////////////////////////////
20
21TransformAdapter::TransformAdapter(StreamInterface * stream,
22                                   TransformInterface * transform,
23                                   bool direction_read)
24    : StreamAdapterInterface(stream), transform_(transform),
25      direction_read_(direction_read), state_(ST_PROCESSING), len_(0) {
26}
27
28TransformAdapter::~TransformAdapter() {
29  TransformAdapter::Close();
30  delete transform_;
31}
32
33StreamResult
34TransformAdapter::Read(void * buffer, size_t buffer_len,
35                       size_t * read, int * error) {
36  if (!direction_read_)
37    return SR_EOS;
38
39  while (state_ != ST_ERROR) {
40    if (state_ == ST_COMPLETE)
41      return SR_EOS;
42
43    // Buffer more data
44    if ((state_ == ST_PROCESSING) && (len_ < sizeof(buffer_))) {
45      size_t subread;
46      StreamResult result = StreamAdapterInterface::Read(
47                              buffer_ + len_,
48                              sizeof(buffer_) - len_,
49                              &subread,
50                              &error_);
51      if (result == SR_BLOCK) {
52        return SR_BLOCK;
53      } else if (result == SR_ERROR) {
54        state_ = ST_ERROR;
55        break;
56      } else if (result == SR_EOS) {
57        state_ = ST_FLUSHING;
58      } else {
59        len_ += subread;
60      }
61    }
62
63    // Process buffered data
64    size_t in_len = len_;
65    size_t out_len = buffer_len;
66    StreamResult result = transform_->Transform(buffer_, &in_len,
67                                                buffer, &out_len,
68                                                (state_ == ST_FLUSHING));
69    ASSERT(result != SR_BLOCK);
70    if (result == SR_EOS) {
71      // Note: Don't signal SR_EOS this iteration, unless out_len is zero
72      state_ = ST_COMPLETE;
73    } else if (result == SR_ERROR) {
74      state_ = ST_ERROR;
75      error_ = -1; // TODO: propagate error
76      break;
77    } else if ((out_len == 0) && (state_ == ST_FLUSHING)) {
78      // If there is no output AND no more input, then something is wrong
79      state_ = ST_ERROR;
80      error_ = -1; // TODO: better error code?
81      break;
82    }
83
84    len_ -= in_len;
85    if (len_ > 0)
86      memmove(buffer_, buffer_ + in_len, len_);
87
88    if (out_len == 0)
89      continue;
90
91    if (read)
92      *read = out_len;
93    return SR_SUCCESS;
94  }
95
96  if (error)
97    *error = error_;
98  return SR_ERROR;
99}
100
101StreamResult
102TransformAdapter::Write(const void * data, size_t data_len,
103                        size_t * written, int * error) {
104  if (direction_read_)
105    return SR_EOS;
106
107  size_t bytes_written = 0;
108  while (state_ != ST_ERROR) {
109    if (state_ == ST_COMPLETE)
110      return SR_EOS;
111
112    if (len_ < sizeof(buffer_)) {
113      // Process buffered data
114      size_t in_len = data_len;
115      size_t out_len = sizeof(buffer_) - len_;
116      StreamResult result = transform_->Transform(data, &in_len,
117                                                  buffer_ + len_, &out_len,
118                                                  (state_ == ST_FLUSHING));
119
120      ASSERT(result != SR_BLOCK);
121      if (result == SR_EOS) {
122        // Note: Don't signal SR_EOS this iteration, unless no data written
123        state_ = ST_COMPLETE;
124      } else if (result == SR_ERROR) {
125        ASSERT(false); // When this happens, think about what should be done
126        state_ = ST_ERROR;
127        error_ = -1; // TODO: propagate error
128        break;
129      }
130
131      len_ = out_len;
132      bytes_written = in_len;
133    }
134
135    size_t pos = 0;
136    while (pos < len_) {
137      size_t subwritten;
138      StreamResult result = StreamAdapterInterface::Write(buffer_ + pos,
139                                                          len_ - pos,
140                                                          &subwritten,
141                                                          &error_);
142      if (result == SR_BLOCK) {
143        ASSERT(false); // TODO: we should handle this
144        return SR_BLOCK;
145      } else if (result == SR_ERROR) {
146        state_ = ST_ERROR;
147        break;
148      } else if (result == SR_EOS) {
149        state_ = ST_COMPLETE;
150        break;
151      }
152
153      pos += subwritten;
154    }
155
156    len_ -= pos;
157    if (len_ > 0)
158      memmove(buffer_, buffer_ + pos, len_);
159
160    if (bytes_written == 0)
161      continue;
162
163    if (written)
164      *written = bytes_written;
165    return SR_SUCCESS;
166  }
167
168  if (error)
169    *error = error_;
170  return SR_ERROR;
171}
172
173void
174TransformAdapter::Close() {
175  if (!direction_read_ && (state_ == ST_PROCESSING)) {
176    state_ = ST_FLUSHING;
177    do {
178      Write(0, 0, NULL, NULL);
179    } while (state_ == ST_FLUSHING);
180  }
181  state_ = ST_COMPLETE;
182  StreamAdapterInterface::Close();
183}
184
185} // namespace rtc
186