1 /*
2  *
3  * Copyright (C) 2018 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include "client_socket.h"
18 #include "sdl_wrapper.h"
19 
20 #include "android-base/logging.h"
21 #include "gflags/gflags.h"
22 #include "opuscpp/opus_wrapper.h"
23 #include <SDL2/SDL.h>
24 
25 #include <cstdint>
26 #include <tuple>
27 #include <vector>
28 
29 DEFINE_int32(
30     device_num, 1,
31     "Cuttlefish device number, corresponding to username vsoc-## number");
32 
33 namespace {
AudioPort()34 std::uint16_t AudioPort() {
35   constexpr std::uint16_t kAudioStreamBasePort = 7444;
36   std::uint16_t audio_port = kAudioStreamBasePort + (FLAGS_device_num - 1);
37   return audio_port;
38 }
39 
Connect()40 cfp::ClientSocket Connect() {
41   const auto port = AudioPort();
42   auto conn = cfp::ClientSocket{port};
43   if (!conn.valid()) {
44     LOG(FATAL) << "couldn't connect on port " << port;
45   }
46   return conn;
47 }
48 
RecvHeader(cfp::ClientSocket * conn)49 std::tuple<std::uint16_t, std::uint16_t> RecvHeader(cfp::ClientSocket* conn) {
50   // creating variables because these must be received in order
51   auto num_channels = conn->RecvUInt16();
52   auto frame_rate = conn->RecvUInt16();
53   LOG(INFO) << "\nnum_channels: " << num_channels
54             << "\nframe_rate: " << frame_rate << '\n';
55   return {num_channels, frame_rate};
56 }
57 
58 // Returns frame_size and encoded audio
RecvEncodedAudio(cfp::ClientSocket * conn)59 std::tuple<std::uint32_t, std::vector<unsigned char>> RecvEncodedAudio(
60     cfp::ClientSocket* conn) {
61   auto length = conn->RecvUInt32();
62   auto frame_size = conn->RecvUInt32();
63   auto encoded = conn->RecvAll(length);
64 
65   if (encoded.size() < length) {
66     encoded.clear();
67   }
68   return {frame_size, std::move(encoded)};
69 }
70 
PlayDecodedAudio(cfp::SDLAudioDevice * audio_device,const std::vector<opus_int16> & audio)71 void PlayDecodedAudio(cfp::SDLAudioDevice* audio_device,
72                       const std::vector<opus_int16>& audio) {
73   auto sz = audio.size() * sizeof audio[0];
74   auto ret = audio_device->QueueAudio(audio.data(), sz);
75   if (ret < 0) {
76     LOG(ERROR) << "failed to queue audio: " << SDL_GetError() << '\n';
77   }
78 }
79 
80 }  // namespace
81 
main(int argc,char * argv[])82 int main(int argc, char* argv[]) {
83   ::google::InitGoogleLogging(argv[0]);
84   ::gflags::ParseCommandLineFlags(&argc, &argv, true);
85   cfp::SDLLib sdl{};
86 
87   auto conn = Connect();
88   const auto& [num_channels, frame_rate] = RecvHeader(&conn);
89 
90   auto audio_device = sdl.OpenAudioDevice(frame_rate, num_channels);
91   auto dec =
92       opus::Decoder{static_cast<std::uint32_t>(frame_rate), num_channels};
93   CHECK(dec.valid()) << "Could not construct Decoder. Maybe bad frame_rate ("
94                      << frame_rate <<") or num_channels (" << num_channels
95                      << ")?";
96 
97   while (true) {
98     CHECK(dec.valid()) << "decoder in invalid state";
99     const auto& [frame_size, encoded] = RecvEncodedAudio(&conn);
100     if (encoded.empty()) {
101       break;
102     }
103     auto decoded = dec.Decode(encoded, frame_size, false);
104     if (decoded.empty()) {
105       break;
106     }
107     PlayDecodedAudio(&audio_device, decoded);
108   }
109 }
110