5a0c4ad254c6798b055658217afc1419d0a4dc97
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / platform / sdl / audio_sink.cpp
1 /*
2  * Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 3, as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranties of
10  * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11  * PURPOSE.  See the GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17
18 #include "anbox/platform/sdl/audio_sink.h"
19 #include "anbox/logger.h"
20
21 #include <stdexcept>
22
23 #include <boost/throw_exception.hpp>
24
25 namespace {
26 const constexpr size_t max_queue_size{16};
27 }
28
29 namespace anbox {
30 namespace platform {
31 namespace sdl {
32 AudioSink::AudioSink() :
33   device_id_(0),
34   queue_(max_queue_size) {
35 }
36
37 AudioSink::~AudioSink() {}
38
39 void AudioSink::on_data_requested(void *user_data, std::uint8_t *buffer, int size) {
40   auto thiz = static_cast<AudioSink*>(user_data);
41   thiz->read_data(buffer, size);
42 }
43
44 bool AudioSink::connect_audio() {
45   if (device_id_ > 0)
46     return true;
47
48   SDL_memset(&spec_, 0, sizeof(spec_));
49   spec_.freq = 44100;
50   spec_.format = AUDIO_S16;
51   spec_.channels = 2;
52   spec_.samples = 1024;
53   spec_.callback = &AudioSink::on_data_requested;
54   spec_.userdata = this;
55
56   device_id_ = SDL_OpenAudioDevice(nullptr, 0, &spec_, nullptr, 0);
57   if (!device_id_)
58     return false;
59
60   SDL_PauseAudioDevice(device_id_, 0);
61
62   return true;
63 }
64
65 void AudioSink::disconnect_audio() {
66   if (device_id_ == 0)
67     return;
68
69   SDL_CloseAudioDevice(device_id_);
70   device_id_ = 0;
71 }
72
73 void AudioSink::read_data(std::uint8_t *buffer, int size) {
74   std::unique_lock<std::mutex> l(lock_);
75   const auto wanted = size;
76   int count = 0;
77   auto dst = buffer;
78
79   while (count < wanted) {
80     if (read_buffer_left_ > 0) {
81       size_t avail = std::min<size_t>(wanted - count, read_buffer_left_);
82       memcpy(dst + count,
83              read_buffer_.data() + (read_buffer_.size() - read_buffer_left_),
84              avail);
85       count += avail;
86       read_buffer_left_ -= avail;
87       continue;
88     }
89
90     bool blocking = (count == 0);
91     auto result = -EIO;
92     if (blocking)
93       result = queue_.pop_locked(&read_buffer_, l);
94     else
95       result = queue_.try_pop_locked(&read_buffer_);
96
97     if (result == 0) {
98       read_buffer_left_ = read_buffer_.size();
99       continue;
100     }
101
102     if (count > 0) break;
103
104     return;
105   }
106 }
107
108 void AudioSink::write_data(const std::vector<std::uint8_t> &data) {
109   std::unique_lock<std::mutex> l(lock_);
110   if (!connect_audio()) {
111     WARNING("Audio server not connected, skipping %d bytes", data.size());
112     return;
113   }
114   graphics::Buffer buffer{data.data(), data.data() + data.size()};
115   queue_.push_locked(std::move(buffer), l);
116 }
117 } // namespace sdl
118 } // namespace platform
119 } // namespace anbox