1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fbl/ref_ptr.h>
8 #include <lib/simple-audio-stream/simple-audio-stream.h>
9 #include <zircon/device/audio.h>
10 
11 #include "vim-audio-utils.h"
12 
13 // Fwd Decls
14 extern "C" {
15     struct vim2_display;
16 }
17 
18 namespace audio {
19 namespace vim2 {
20 
21 class Vim2SpdifAudioStream : public SimpleAudioStream {
22   public:
23     DISALLOW_COPY_ASSIGN_AND_MOVE(Vim2SpdifAudioStream);
24     static void Disable(const Registers& regs);
25 
display_id()26     uint64_t display_id() const { return display_id_; }
27 
28   protected:
29     friend class fbl::RefPtr<Vim2SpdifAudioStream>;
30     friend class SimpleAudioStream;
31 
32     Vim2SpdifAudioStream(const vim2_display* display,
33                          fbl::RefPtr<Registers> regs,
34                          fbl::RefPtr<RefCountedVmo> ring_buffer_vmo,
35                          fzl::PinnedVmo pinned_ring_buffer,
36                          uint64_t display_id);
37 
~Vim2SpdifAudioStream()38     ~Vim2SpdifAudioStream() override {
39         Shutdown();
40     }
41 
42     zx_status_t Init() __TA_REQUIRES(domain_->token()) override;
43     void ShutdownHook() __TA_REQUIRES(domain_->token()) override;
44     void RingBufferShutdown() __TA_REQUIRES(domain_->token()) override;
45 
46     zx_status_t ChangeFormat(const audio_proto::StreamSetFmtReq& req)
47         __TA_REQUIRES(domain_->token()) override;
48     zx_status_t SetGain(const audio_proto::SetGainReq& req)
49         __TA_REQUIRES(domain_->token()) override;
50 
51     zx_status_t GetBuffer(const audio_proto::RingBufGetBufferReq& req,
52                           uint32_t* out_num_rb_frames,
53                           zx::vmo* out_buffer) __TA_REQUIRES(domain_->token()) override;
54     zx_status_t Start(uint64_t* out_start_time) __TA_REQUIRES(domain_->token()) override;
55     zx_status_t Stop() __TA_REQUIRES(domain_->token()) override;
56 
57   private:
58     zx_status_t CreateFormatList() __TA_REQUIRES(domain_->token());
59 
60     void Enable();
61     void SetupBuffer();
62     void SetMode(uint32_t frame_rate, audio_sample_format_t fmt);
63     void Mute(bool muted);
64 
65     // TODO(johngro) : it is unfortunate that we need to maintain an unmanaged
66     // pointer back to our display in order to configure it properly when
67     // setting audio modes.  In a perfect world, however, we would really not
68     // know much of anything about us.  Instead, we would be able to properly
69     // represent composite device drivers, and this audio code would be running
70     // on its own in a separate devhost and acting as a DAI driver for various
71     // codec drivers.  In this world, HDMI driver would serve as a codec driver,
72     // and it would get first crack at the call to "set format", which would
73     // allow it configure the audio clock recover and audio info-frame as part
74     // of the process of requesting the proper DAI stream to feed the HDMI
75     // transmitter unit in the chip.
76     //
77     // Until that day comes, however, we need a small callback hook into the
78     // display driver to set this up when the high level code asks us to do so.
79     // In order to do that, we need to hold the context pointer to the display
80     // driver instance, which will be passed to us at construction time.  Since
81     // we have no managed pointers, it is the HDMI driver's responsibility to
82     // make certain that its scope outlives our.
83     //
84     const struct vim2_display* const display_;
85     const uint64_t display_id_;
86 
87     fbl::RefPtr<Registers> regs_;
88     fbl::RefPtr<RefCountedVmo> ring_buffer_vmo_;
89     fzl::PinnedVmo pinned_ring_buffer_;
90     uint32_t usable_buffer_size_ = 0;
91 };
92 
93 }  // namespace vim2
94 }  // namespace audio
95