এক্সোপ্লেয়ার লাইব্রেরির মূল অংশে রয়েছে Player
ইন্টারফেস। একটি Player
প্রথাগত উচ্চ-স্তরের মিডিয়া প্লেয়ার কার্যকারিতা যেমন মিডিয়া বাফার করার ক্ষমতা, খেলা, বিরতি এবং অনুসন্ধান করার ক্ষমতা প্রকাশ করে। ডিফল্ট বাস্তবায়ন ExoPlayer
মিডিয়ার ধরন, কীভাবে এবং কোথায় এটি সংরক্ষণ করা হয় এবং এটি কীভাবে রেন্ডার করা হয় সে সম্পর্কে কিছু অনুমান করার জন্য (এবং তাই কিছু বিধিনিষেধ আরোপ করার জন্য) ডিজাইন করা হয়েছে। সরাসরি মিডিয়ার লোডিং এবং রেন্ডারিং বাস্তবায়নের পরিবর্তে, ExoPlayer
বাস্তবায়নগুলি এই কাজটিকে এমন উপাদানগুলিতে অর্পণ করে যা প্লেয়ার তৈরি করার সময় বা প্লেয়ারের কাছে নতুন মিডিয়া উত্সগুলি পাস করার সময় ইনজেকশন দেওয়া হয়। সমস্ত ExoPlayer
বাস্তবায়নের জন্য সাধারণ উপাদানগুলি হল:
-
MediaSource
দৃষ্টান্তগুলি যে মিডিয়া সংজ্ঞায়িত করে প্লে করা হবে, মিডিয়া লোড হবে এবং যেখান থেকে লোড করা মিডিয়া পড়া যাবে। প্লেয়ারের ভিতরে একটিMediaSource.Factory
দ্বারা একটিMediaItem
থেকে একটিMediaSource
উদাহরণ তৈরি করা হয়। এগুলি মিডিয়া সোর্স ভিত্তিক প্লেলিস্ট API ব্যবহার করে সরাসরি প্লেয়ারের কাছে প্রেরণ করা যেতে পারে। - একটি
MediaSource.Factory
উদাহরণ যা একটিMediaItem
কে একটিMediaSource
এ রূপান্তর করে। প্লেয়ার তৈরি করা হলেMediaSource.Factory
ইনজেকশন দেওয়া হয়। -
Renderer
দৃষ্টান্ত যা মিডিয়ার পৃথক উপাদান রেন্ডার করে। প্লেয়ার তৈরি করা হলে এগুলো ইনজেকশন দেওয়া হয়। - একটি
TrackSelector
যেটিMediaSource
দ্বারা প্রদত্ত ট্র্যাকগুলিকে প্রতিটি উপলব্ধRenderer
দ্বারা ব্যবহার করার জন্য নির্বাচন করে৷ প্লেয়ার তৈরি করার সময় একটিTrackSelector
ইনজেকশন দেওয়া হয়। - একটি
LoadControl
যা নিয়ন্ত্রণ করে কখনMediaSource
আরও মিডিয়া বাফার করে এবং কতটা মিডিয়া বাফার হয়। প্লেয়ার তৈরি করার সময় একটিLoadControl
ইনজেকশন দেওয়া হয়। - একটি
LivePlaybackSpeedControl
যা লাইভ প্লেব্যাকের সময় প্লেব্যাকের গতি নিয়ন্ত্রণ করে যাতে প্লেয়ারকে কনফিগার করা লাইভ অফসেটের কাছাকাছি থাকতে দেয়। প্লেয়ার তৈরি করার সময় একটিLivePlaybackSpeedControl
ইনজেকশন দেওয়া হয়।
প্লেয়ার কার্যকারিতার টুকরোগুলি বাস্তবায়ন করে এমন উপাদানগুলিকে ইনজেকশন দেওয়ার ধারণাটি লাইব্রেরি জুড়ে উপস্থিত রয়েছে। কিছু উপাদানের ডিফল্ট বাস্তবায়ন আরও ইনজেকশনের উপাদানগুলিতে কাজ করে। এটি একটি কাস্টম উপায়ে কনফিগার করা বাস্তবায়নের সাথে অনেক সাব-কম্পোনেন্টকে পৃথকভাবে প্রতিস্থাপন করার অনুমতি দেয়।
প্লেয়ার কাস্টমাইজেশন
কম্পোনেন্ট ইনজেকশন দিয়ে প্লেয়ার কাস্টমাইজ করার কিছু সাধারণ উদাহরণ নিচে বর্ণনা করা হয়েছে।
নেটওয়ার্ক স্ট্যাক কনফিগার করা হচ্ছে
ExoPlayer দ্বারা ব্যবহৃত নেটওয়ার্ক স্ট্যাক কাস্টমাইজ করার বিষয়ে আমাদের একটি পৃষ্ঠা রয়েছে।
নেটওয়ার্ক থেকে লোড করা ডেটা ক্যাশিং
অস্থায়ী অন-দ্য-ফ্লাই ক্যাশিং এবং মিডিয়া ডাউনলোড করার জন্য গাইড দেখুন।
সার্ভার মিথস্ক্রিয়া কাস্টমাইজ করা
কিছু অ্যাপ্লিকেশান HTTP অনুরোধ এবং প্রতিক্রিয়া বাধা দিতে চাইতে পারে৷ আপনি কাস্টম রিকোয়েস্ট হেডার ইনজেক্ট করতে চাইতে পারেন, সার্ভারের রেসপন্স হেডার পড়তে, অনুরোধের ইউআরআই পরিবর্তন করতে পারেন, ইত্যাদি
নিম্নোক্ত উদাহরণ প্রদর্শন করে যে কিভাবে একটি কাস্টম DataSource.Factory
DefaultMediaSourceFactory
তে ইনজেক্ট করে এই আচরণগুলি বাস্তবায়ন করা যায়:
কোটলিন
val dataSourceFactory = DataSource.Factory { val dataSource = httpDataSourceFactory.createDataSource() // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value") dataSource } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory) ) .build()
জাভা
DataSource.Factory dataSourceFactory = () -> { HttpDataSource dataSource = httpDataSourceFactory.createDataSource(); // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value"); return dataSource; }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)) .build();
উপরের কোড স্নিপেটে, ইনজেকশন করা HttpDataSource
প্রতিটি HTTP অনুরোধে হেডার "Header: Value"
অন্তর্ভুক্ত করে। এই আচরণ একটি HTTP উৎসের সাথে প্রতিটি মিথস্ক্রিয়া জন্য স্থির করা হয়.
আরও দানাদার পদ্ধতির জন্য, আপনি একটি ResolvingDataSource
ব্যবহার করে ঠিক সময়ে আচরণ ইনজেক্ট করতে পারেন। নিম্নলিখিত কোড স্নিপেট দেখায় কিভাবে একটি HTTP উৎসের সাথে ইন্টারঅ্যাক্ট করার আগে অনুরোধ শিরোনামগুলি ইনজেকশন করতে হয়:
কোটলিন
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time request headers. dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)) }
জাভা
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time request headers. dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)));
আপনি একটি ResolvingDataSource
ব্যবহার করতে পারেন URI-এর ঠিক সময়ে পরিবর্তন করতে, যেমনটি নিম্নলিখিত স্নিপেটে দেখানো হয়েছে:
কোটলিন
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time URI resolution logic. dataSpec.withUri(resolveUri(dataSpec.uri)) }
জাভা
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time URI resolution logic. dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri)));
ত্রুটি হ্যান্ডলিং কাস্টমাইজ করা
একটি কাস্টম LoadErrorHandlingPolicy
প্রয়োগ করা অ্যাপগুলিকে ExoPlayer যেভাবে লোড ত্রুটির প্রতিক্রিয়া জানায় তা কাস্টমাইজ করতে দেয়৷ উদাহরণস্বরূপ, একটি অ্যাপ অনেকবার পুনরায় চেষ্টা করার পরিবর্তে দ্রুত ব্যর্থ হতে চাইতে পারে বা ব্যাক-অফ লজিক কাস্টমাইজ করতে চাইতে পারে যা নিয়ন্ত্রণ করে যে প্লেয়ার প্রতিটি পুনঃপ্রচেষ্টার মধ্যে কতক্ষণ অপেক্ষা করবে। নিম্নোক্ত স্নিপেটটি দেখায় কিভাবে কাস্টম ব্যাক-অফ যুক্তি প্রয়োগ করতে হয়:
কোটলিন
val loadErrorHandlingPolicy: LoadErrorHandlingPolicy = object : DefaultLoadErrorHandlingPolicy() { override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo): Long { // Implement custom back-off logic here. return 0 } } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) ) .build()
জাভা
LoadErrorHandlingPolicy loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy() { @Override public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) { // Implement custom back-off logic here. return 0; } }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)) .build();
LoadErrorInfo
আর্গুমেন্টে ত্রুটির প্রকার বা ব্যর্থ অনুরোধের উপর ভিত্তি করে যুক্তি কাস্টমাইজ করতে ব্যর্থ লোড সম্পর্কে আরও তথ্য রয়েছে।
এক্সট্রাক্টর পতাকা কাস্টমাইজ করা
এক্সট্র্যাক্টর ফ্ল্যাগগুলি প্রগতিশীল মিডিয়া থেকে পৃথক ফর্ম্যাটগুলি কীভাবে বের করা হয় তা কাস্টমাইজ করতে ব্যবহার করা যেতে পারে। সেগুলি DefaultExtractorsFactory
এ সেট করা যেতে পারে যা DefaultMediaSourceFactory
কে দেওয়া হয়। নিম্নলিখিত উদাহরণটি একটি পতাকা পাস করে যা MP3 স্ট্রিমগুলির জন্য সূচক-ভিত্তিক চাওয়াকে সক্ষম করে।
কোটলিন
val extractorsFactory = DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING) val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory)) .build()
জাভা
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING); ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory(new DefaultMediaSourceFactory(context, extractorsFactory)) .build();
ধ্রুবক বিটরেট চাওয়া সক্রিয় করা হচ্ছে
MP3, ADTS এবং AMR স্ট্রীমগুলির জন্য, আপনি FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
পতাকাগুলির সাথে একটি ধ্রুবক বিটরেট অনুমান ব্যবহার করে আনুমানিক অনুসন্ধান সক্ষম করতে পারেন৷ এই পতাকাগুলি উপরে বর্ণিত হিসাবে পৃথক DefaultExtractorsFactory.setXyzExtractorFlags
পদ্ধতি ব্যবহার করে পৃথক নিষ্কাশনকারীদের জন্য সেট করা যেতে পারে। এটিকে সমর্থন করে এমন সমস্ত এক্সট্র্যাক্টরগুলির জন্য ধ্রুবক বিটরেট অনুসন্ধান সক্ষম করতে, DefaultExtractorsFactory.setConstantBitrateSeekingEnabled
ব্যবহার করুন।
কোটলিন
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
জাভা
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
ExtractorsFactory
DefaultMediaSourceFactory
মাধ্যমে ইনজেকশন দেওয়া যেতে পারে যেমন উপরে বর্ণিত এক্সট্র্যাক্টর ফ্ল্যাগগুলি কাস্টমাইজ করার জন্য।
অ্যাসিঙ্ক্রোনাস বাফার সারি চালু করা হচ্ছে
অ্যাসিঙ্ক্রোনাস বাফার সারি হল ExoPlayer-এর রেন্ডারিং পাইপলাইনের একটি বর্ধন, যা MediaCodec
দৃষ্টান্তগুলিকে অ্যাসিঙ্ক্রোনাস মোডে পরিচালনা করে এবং ডেটার ডিকোডিং এবং রেন্ডারিং শিডিউল করতে অতিরিক্ত থ্রেড ব্যবহার করে। এটি সক্ষম করলে ড্রপ করা ফ্রেম এবং অডিও আন্ডাররান কমাতে পারে।
অ্যাসিঙ্ক্রোনাস বাফার সারিগুলি Android 12 (API স্তর 31) এবং তার উপরে চলমান ডিভাইসগুলিতে ডিফল্টরূপে সক্ষম করা হয় এবং Android 6.0 (API স্তর 23) দিয়ে শুরু করে ম্যানুয়ালি সক্ষম করা যেতে পারে। নির্দিষ্ট ডিভাইসগুলির জন্য বৈশিষ্ট্যটি সক্ষম করার কথা বিবেচনা করুন যেখানে আপনি ড্রপ করা ফ্রেম বা অডিও আন্ডাররান দেখেন, বিশেষ করে যখন DRM সুরক্ষিত বা উচ্চ-ফ্রেম-রেট সামগ্রী বাজানো হয়।
সবচেয়ে সহজ ক্ষেত্রে, আপনাকে প্লেয়ারে একটি DefaultRenderersFactory
নিম্নরূপ ইনজেক্ট করতে হবে:
কোটলিন
val renderersFactory = DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing() val exoPlayer = ExoPlayer.Builder(context, renderersFactory).build()
জাভা
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing(); ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory).build();
আপনি যদি রেন্ডারারদের সরাসরি ইনস্ট্যান্টিয়েটিং করেন, তাহলে MediaCodecVideoRenderer
এবং MediaCodecAudioRenderer
কনস্ট্রাক্টরদের কাছে একটি AsynchronousMediaCodecAdapter.Factory
পাস করুন।
ForwardingSimpleBasePlayer
এর সাথে কাস্টমাইজ করা অপারেশন
আপনি ForwardingSimpleBasePlayer
এর একটি সাবক্লাসে মোড়ানো Player
উদাহরণের কিছু আচরণ কাস্টমাইজ করতে পারেন। এই ক্লাসটি আপনাকে Player
পদ্ধতিগুলি সরাসরি প্রয়োগ করার পরিবর্তে নির্দিষ্ট 'অপারেশন' বাধা দিতে দেয়। এটি সুসংগত আচরণ নিশ্চিত করে, উদাহরণস্বরূপ, play()
, pause()
এবং setPlayWhenReady(boolean)
। এটি নিশ্চিত করে যে সমস্ত রাজ্য পরিবর্তনগুলি নিবন্ধিত Player.Listener
দৃষ্টান্তগুলিতে সঠিকভাবে প্রচারিত হয়েছে৷ বেশিরভাগ কাস্টমাইজেশন ব্যবহারের ক্ষেত্রে ForwardingSimpleBasePlayer
এই সামঞ্জস্যতার গ্যারান্টিগুলির কারণে আরও ত্রুটি-প্রবণ ForwardingPlayer
চেয়ে পছন্দ করা উচিত।
উদাহরণস্বরূপ, প্লেব্যাক শুরু বা বন্ধ করার সময় কিছু কাস্টম যুক্তি যোগ করতে:
কোটলিন
class PlayerWithCustomPlay(player: Player) : ForwardingSimpleBasePlayer(player) { override fun handleSetPlayWhenReady(playWhenReady: Boolean): ListenableFuture<*> { // Add custom logic return super.handleSetPlayWhenReady(playWhenReady) } }
জাভা
class PlayerWithCustomPlay extends ForwardingSimpleBasePlayer { public PlayerWithCustomPlay(Player player) { super(player); } @Override protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) { // Add custom logic return super.handleSetPlayWhenReady(playWhenReady); } }
অথবা SEEK_TO_NEXT
কমান্ডের অনুমতি না দিতে (এবং নিশ্চিত করুন Player.seekToNext
একটি নো-অপ):
কোটলিন
class PlayerWithoutSeekToNext(player: Player) : ForwardingSimpleBasePlayer(player) { override fun getState(): State { val state = super.getState() return state .buildUpon() .setAvailableCommands( state.availableCommands.buildUpon().remove(COMMAND_SEEK_TO_NEXT).build() ) .build() } // We don't need to override handleSeek, because it is guaranteed not to be called for // COMMAND_SEEK_TO_NEXT since we've marked that command unavailable. }
জাভা
class PlayerWithoutSeekToNext extends ForwardingSimpleBasePlayer { public PlayerWithoutSeekToNext(Player player) { super(player); } @Override protected State getState() { State state = super.getState(); return state .buildUpon() .setAvailableCommands( state.availableCommands.buildUpon().remove(COMMAND_SEEK_TO_NEXT).build()) .build(); } // We don't need to override handleSeek, because it is guaranteed not to be called for // COMMAND_SEEK_TO_NEXT since we've marked that command unavailable. }
মিডিয়াসোর্স কাস্টমাইজেশন
উপরের উদাহরণগুলি প্লেয়ারে পাস করা সমস্ত MediaItem
অবজেক্টের প্লেব্যাকের সময় ব্যবহারের জন্য কাস্টমাইজ করা উপাদানগুলিকে ইনজেক্ট করে৷ যেখানে সূক্ষ্ম কাস্টমাইজেশন প্রয়োজন, সেখানে পৃথক MediaSource
দৃষ্টান্তগুলিতে কাস্টমাইজ করা উপাদানগুলি ইনজেকশন করাও সম্ভব, যা সরাসরি প্লেয়ারের কাছে প্রেরণ করা যেতে পারে। নীচের উদাহরণটি দেখায় যে কীভাবে একটি কাস্টম DataSource.Factory
ফ্যাক্টরি, ExtractorsFactory
এবং LoadErrorHandlingPolicy
ব্যবহার করতে একটি ProgressiveMediaSource
কাস্টমাইজ করা যায়:
কোটলিন
val mediaSource = ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri))
জাভা
ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri));
কাস্টম উপাদান তৈরি
লাইব্রেরি সাধারণ ব্যবহারের ক্ষেত্রে এই পৃষ্ঠার শীর্ষে তালিকাভুক্ত উপাদানগুলির ডিফল্ট বাস্তবায়ন প্রদান করে। একটি ExoPlayer
এই উপাদানগুলি ব্যবহার করতে পারে, তবে অ-মানক আচরণের প্রয়োজন হলে কাস্টম বাস্তবায়ন ব্যবহার করার জন্য তৈরি করা যেতে পারে। কাস্টম বাস্তবায়নের জন্য কিছু ব্যবহারের ক্ষেত্রে হল:
-
Renderer
- লাইব্রেরি দ্বারা প্রদত্ত ডিফল্ট বাস্তবায়ন দ্বারা সমর্থিত নয় এমন একটি মিডিয়া টাইপ পরিচালনা করতে আপনি একটি কাস্টমRenderer
প্রয়োগ করতে চাইতে পারেন। -
TrackSelector
- একটি কাস্টমTrackSelector
প্রয়োগ করা একটি অ্যাপ ডেভেলপারকে যেভাবেMediaSource
দ্বারা প্রকাশ করা ট্র্যাকগুলি উপলব্ধ প্রতিটিRenderer
দ্বারা ব্যবহারের জন্য নির্বাচন করা হয় তা পরিবর্তন করতে দেয়৷ -
LoadControl
- একটি কাস্টমLoadControl
প্রয়োগ করা একটি অ্যাপ বিকাশকারীকে প্লেয়ারের বাফারিং নীতি পরিবর্তন করতে দেয়। -
Extractor
- আপনি যদি বর্তমানে লাইব্রেরি দ্বারা সমর্থিত নয় এমন একটি ধারক বিন্যাস সমর্থন করতে চান তবে একটি কাস্টমExtractor
ক্লাস বাস্তবায়ন বিবেচনা করুন। -
MediaSource
- একটি কাস্টমMediaSource
ক্লাস বাস্তবায়ন করা উপযুক্ত হতে পারে যদি আপনি একটি কাস্টম উপায়ে রেন্ডারারদের খাওয়ানোর জন্য মিডিয়া নমুনা পেতে চান, অথবা আপনি যদি কাস্টমMediaSource
কম্পোজিটিং আচরণ বাস্তবায়ন করতে চান। -
MediaSource.Factory
– একটি কাস্টমMediaSource.Factory
বাস্তবায়ন করা। ফ্যাক্টরি একটি অ্যাপ্লিকেশনকে একটিMediaItem
থেকেMediaSource
তৈরি করার উপায় কাস্টমাইজ করার অনুমতি দেয়৷ -
DataSource
- ExoPlayer-এর আপস্ট্রিম প্যাকেজে ইতিমধ্যেই বিভিন্ন ব্যবহারের ক্ষেত্রে অনেকগুলিDataSource
বাস্তবায়ন রয়েছে৷ আপনি অন্য উপায়ে ডেটা লোড করার জন্য আপনার নিজস্বDataSource
ক্লাস বাস্তবায়ন করতে চাইতে পারেন, যেমন একটি কাস্টম প্রোটোকলের মাধ্যমে, একটি কাস্টম HTTP স্ট্যাক ব্যবহার করে, বা একটি কাস্টম স্থায়ী ক্যাশে থেকে।
কাস্টম উপাদান নির্মাণ করার সময়, আমরা নিম্নলিখিত সুপারিশ:
- যদি একটি কাস্টম কম্পোনেন্টের ইভেন্টগুলিকে অ্যাপে রিপোর্ট করার প্রয়োজন হয়, তাহলে আমরা সুপারিশ করি যে আপনি বিদ্যমান ExoPlayer উপাদানগুলির মতো একই মডেল ব্যবহার করুন, উদাহরণস্বরূপ,
EventDispatcher
ক্লাস ব্যবহার করা বা কম্পোনেন্টের কনস্ট্রাক্টরের সাথে একজন শ্রোতার সাথে একটিHandler
পাস করা। - আমরা সুপারিশ করেছি যে কাস্টম উপাদানগুলি প্লেব্যাকের সময় অ্যাপ দ্বারা পুনরায় কনফিগারেশনের অনুমতি দেওয়ার জন্য বিদ্যমান ExoPlayer উপাদানগুলির মতো একই মডেল ব্যবহার করে৷ এটি করার জন্য, কাস্টম উপাদানগুলিকে
PlayerMessage.Target
প্রয়োগ করতে হবে এবংhandleMessage
পদ্ধতিতে কনফিগারেশন পরিবর্তনগুলি গ্রহণ করতে হবে৷ অ্যাপ্লিকেশন কোডটি ExoPlayer-এরcreateMessage
পদ্ধতিতে কল করে, বার্তাটি কনফিগার করে এবংPlayerMessage.send
ব্যবহার করে কম্পোনেন্টে পাঠানোর মাধ্যমে কনফিগারেশন পরিবর্তনগুলি পাস করতে হবে। প্লেব্যাক থ্রেডে পাঠানোর জন্য বার্তা পাঠানো নিশ্চিত করে যে প্লেয়ারে অন্য যেকোন ক্রিয়াকলাপ সম্পাদিত হওয়ার সাথে সাথে সেগুলি কার্যকর করা হয়েছে।