blob: 2594396f1984d73ae4819650bd8749beda906693 [file] [log] [blame]
Ryan Haining2c1efe62018-12-20 17:44:33 -08001/*
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 "glog/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
29DEFINE_int32(
30 device_num, 1,
31 "Cuttlefish device number, corresponding to username vsoc-## number");
32
33namespace {
34std::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
40cfp::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
49std::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
59std::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
71void 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
82int 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}