1/*
2 *  Copyright (c) 2013 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/modules/audio_device/android/low_latency_event.h"
12
13#include <assert.h>
14
15#define HANDLE_EINTR(x) ({                \
16      typeof(x) eintr_wrapper_result;     \
17      do {                                                        \
18        eintr_wrapper_result = (x);                               \
19      } while (eintr_wrapper_result == -1 && errno == EINTR);     \
20      eintr_wrapper_result;                                       \
21    })
22
23#define IGNORE_EINTR(x) ({                \
24      typeof(x) eintr_wrapper_result;     \
25      do {                                                        \
26        eintr_wrapper_result = (x);                               \
27        if (eintr_wrapper_result == -1 && errno == EINTR) {       \
28          eintr_wrapper_result = 0;                               \
29        }                                                         \
30      } while (0);                                                \
31      eintr_wrapper_result;                                       \
32    })
33
34namespace webrtc {
35
36const LowLatencyEvent::Handle LowLatencyEvent::kInvalidHandle = -1;
37const int LowLatencyEvent::kReadHandle = 0;
38const int LowLatencyEvent::kWriteHandle = 1;
39
40LowLatencyEvent::LowLatencyEvent() {
41  handles_[kReadHandle] = kInvalidHandle;
42  handles_[kWriteHandle] = kInvalidHandle;
43}
44
45LowLatencyEvent::~LowLatencyEvent() {
46  Stop();
47}
48
49bool LowLatencyEvent::Start() {
50  assert(handles_[kReadHandle] == kInvalidHandle);
51  assert(handles_[kWriteHandle] == kInvalidHandle);
52
53  return socketpair(AF_UNIX, SOCK_STREAM, 0, handles_) == 0;
54}
55
56bool LowLatencyEvent::Stop() {
57  bool ret = Close(&handles_[kReadHandle]) && Close(&handles_[kWriteHandle]);
58  handles_[kReadHandle] = kInvalidHandle;
59  handles_[kWriteHandle] = kInvalidHandle;
60  return ret;
61}
62
63void LowLatencyEvent::SignalEvent(int event_id, int event_msg) {
64  WriteFd(event_id, event_msg);
65}
66
67void LowLatencyEvent::WaitOnEvent(int* event_id, int* event_msg) {
68  ReadFd(event_id, event_msg);
69}
70
71bool LowLatencyEvent::Close(Handle* handle) {
72  if (*handle == kInvalidHandle) {
73    return false;
74  }
75  int retval = IGNORE_EINTR(close(*handle));
76  *handle = kInvalidHandle;
77  return retval == 0;
78}
79
80void LowLatencyEvent::WriteFd(int message_id, int message) {
81  char buffer[sizeof(message_id) + sizeof(message)];
82  size_t bytes = sizeof(buffer);
83  memcpy(buffer, &message_id, sizeof(message_id));
84  memcpy(&buffer[sizeof(message_id)], &message, sizeof(message));
85  ssize_t bytes_written = HANDLE_EINTR(write(handles_[kWriteHandle], buffer,
86                                             bytes));
87  if (bytes_written != static_cast<ssize_t>(bytes)) {
88    assert(false);
89  }
90}
91
92void LowLatencyEvent::ReadFd(int* message_id, int* message) {
93  char buffer[sizeof(message_id) + sizeof(message)];
94  size_t bytes = sizeof(buffer);
95  ssize_t bytes_read = HANDLE_EINTR(read(handles_[kReadHandle], buffer, bytes));
96  if (bytes_read == 0) {
97    *message_id = 0;
98    *message = 0;
99    return;
100  } else if (bytes_read == static_cast<ssize_t>(bytes)) {
101    memcpy(message_id, buffer, sizeof(*message_id));
102    memcpy(message, &buffer[sizeof(*message_id)], sizeof(*message));
103  } else {
104    assert(false);
105  }
106}
107
108}  // namespace webrtc
109