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