blob: c12546181ffbcf1d671e42c3107472fc8d6e6c8b [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_IOS_AUDIO_AUDIO_PLAYBACK_SINK_IOS_H_
#define REMOTING_IOS_AUDIO_AUDIO_PLAYBACK_SINK_IOS_H_
#include <AudioToolbox/AudioToolbox.h>
#include <list>
#include <memory>
#include <string>
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "remoting/client/audio/audio_playback_sink.h"
namespace remoting {
// This is the iOS AudioPlaybackSink implementation that uses AudioQueue for
// playback.
class AudioPlaybackSinkIos : public AudioPlaybackSink {
public:
AudioPlaybackSinkIos();
~AudioPlaybackSinkIos() override;
// AudioPlaybackSink implementations.
void SetDataSupplier(AsyncAudioDataSupplier* supplier) override;
void ResetStreamFormat(const AudioStreamFormat& format) override;
private:
// STOPPED <-----------------------------+------------+
// | Received packet | |
// (Start playback)--------+ | |
// | Failed | Succeeded | Buffer |
// v v | Underrun |
// SCHEDULED_TO_RESET RUNNING---------+ |
// | | |
// | | Sink destructing or | Audio queue
// | | format resetting | destroyed
// +--------------------+--------------------------+
enum class State {
STOPPED,
SCHEDULED_TO_RESET,
RUNNING,
};
// Asks |supplier_| to fill audio data into the given buffer.
void AsyncGetAudioData(AudioQueueBufferRef buffer);
// Callback called when |supplier_| has finished filling data for |buffer|.
void OnAudioDataReceived(AudioQueueBufferRef buffer);
// Callback called when the AudioQueue API finished consuming the audio data.
static void OnBufferDequeued(void* context,
AudioQueueRef outAQ,
AudioQueueBufferRef buffer);
// Starts playback immediately. Posts task to reset the output queue if it
// fails to start.
void StartPlayback();
// Stops playback immediately.
void StopPlayback();
// Disposes the current output queue and its buffers, creates a new queue
// and buffers, and immediately request for audio data from |supplier_|.
void ResetOutputQueue();
// Disposes the current output queue and its buffers.
void DisposeOutputQueue();
// If |err| is not no-error, prints an error log at DFATAL level and disposes
// the current output queue. The sink will then not be running until
// ResetStreamFormat() is called again.
// Returns true if error occurs and the output queue has been disposed.
bool HandleError(OSStatus err, const char* function_name);
THREAD_CHECKER(thread_checker_);
AsyncAudioDataSupplier* supplier_ = nullptr;
// Number of buffers that are currently transferred to |supplier_| for
// priming.
size_t priming_buffers_count_ = 0;
// The current stream format.
AudioStreamBasicDescription stream_format_;
// The output queue. nullptr if ResetStreamFormat() has not been called.
AudioQueueRef output_queue_ = nullptr;
// The current state.
State state_ = State::STOPPED;
base::WeakPtrFactory<AudioPlaybackSinkIos> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AudioPlaybackSinkIos);
};
} // namespace remoting
#endif // REMOTING_IOS_AUDIO_AUDIO_PLAYBACK_SINK_IOS_H_